C++如何使find_if不仅返回应用pred为true的第一个对象

C++ How to make find_if not only return the first object for which applying pred to it is true

本文关键字:pred 应用 true 一个对象 返回 何使 find if C++      更新时间:2023-10-16

这是为了允许用户输入他/她想要搜索的姓名、联系人和地址。我想做的是显示所有应用pred的对象,但我似乎无法使其工作。

static string searchName, searchContact, searchAddress;
bool search_User(User &u)
{ 
   return (u.getName() == searchName && u.getContact() == searchContact && u.getAddress() == searchAddress);
}
void searchUser(vector<User> &u)
{
    cout << "Name of user: ";
    getline(cin, searchName);
    cout << "Contact of tutor: ";
    getline(cin, searchContact);
    cout << "Adress of user: ";
    getline(cin, searchAddress);
    vector<User>::iterator i;
    i = find_if(u.begin(), u.end(), search_User);
    cout << i->getName() << i->getContact() << i->getAddress() << endl;
}

通常的解决方案是使用std::copy_if:

std::vector<User> matches;
std::copy_if(v.begin(), v.end(), std::back_inserter(matches),
    [Name, Contact, Address](User const& u)
    { return u.getName() == Name && u.getContact() == Contact && u.getAddress() == Address;});

或者只写一个经典的循环

for (User& u : users) {
  if (search_User(u) {
    std::cout << u; // Assumes you've implemented operator<<(ostream&, User)
  }
} 

伪代码:

for(iterator i = v.begin(); 
    (i = find_if(i, v.end(), ...)) != v.end(); ++i )
{
    print *i;
}

一种方法是使用std::copy_if(从C++11开始)或std::remove_copy_if,用not1否定谓词——这是我在"为什么没有std::copy_if算法?"的答案中找到的copy_if解决方法。

std::vector<User> result;
std::remove_copy_if(u.begin(), u.end(),
                    std::back_inserter(result),
                    std::not1(std::ptr_fun(search_User)));

另一种方法是使用std::partition算法。

对范围[first,last)中的元素进行重新排序,使谓词p返回true的所有元素位于谓词p返回false的元素之前。
(http://en.cppreference.com/w/cpp/algorithm/partition)

std::vector<User>::const_iterator newend =
    std::partition(u.begin(), u.end(), search_User);

(需要C++11)与MSchangers建议的略有不同的是,在找到匹配项时写入std::cout

#include <iostream> 
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
...
std::ostream& operator<<(std::ostream& a_out, const User& a_user)
{
    std::cout << a_user.getName() << ", " << a_user.getContact() << ", " <<
        a_user.getAddress();
    return a_out;
}
...
std::copy_if(users.begin(),
             users.end(),
             std::ostream_iterator<const User>(std::cout, "n"),
             [name, contact, address](const User& a_user)
             {
                return name    == a_user.getName()    &&
                       contact == a_user.getContact() &&
                       address == a_user.getAddress();
             });

编辑:

要显示"用户未找到"消息,您可以按如下方式修改:

int count = 0;
std::copy_if(users.begin(),
             users.end(),
             std::ostream_iterator<const User>(std::cout, "n"),
             [&count, name, contact, address](const User& a_user) -> bool
             {
                if (name    == a_user.getName()    &&
                    contact == a_user.getContact() &&
                    address == a_user.getAddress())
                {
                    count++;
                    return true;
                }
                return false;
             });
if (!count) std::cout << "User not foundn";

您可以通过递增find_if()的返回值并将其传递给后续调用来循环所有命中,例如:

// Switched to const_iterator, purely because the example code wasn't
// changing the elements found.
vector<User>::const_iterator i = find_if(u.begin(), u.end(), search_User);
while (i != u.end())
{
    cout << i->getName() << i->getContact() << i->getAddress() << endl;
    ++i;
    i = find_if(i, u.end(), search_User);
}

对于C++14,我的首选解决方案是使用std::copy_if并返回所有匹配的向量,并传入保持分区所需的参数:

std::vector<User> findMatches( const std::vector<User> &v) {
    std::vector<User> matches;
    std::copy_if(v.begin(), v.end(), std::back_inserter(matches),
    [Name, Contact, Address](User& u)
    { 
         return(u.getName() == Name 
             && u.getContact() == Contact 
             && u.getAddress() == Address);
    });
    return matches;
}

@MSchangers目前发布的顶级解决方案在lambda中有一个错误,该错误缺少一个return语句。

https://godbolt.org/g/CQOXzv

http://cpp.sh/2j7q7

$ g++-5 -std=c++14 user.cpp -o test.bin
$ ./test.bin

要在命令行中编译,请将以下内容保存为user.cpp,然后运行:

#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
class User {
    public:
        std::string Name;
        std::string Contact;
        std::string Address;
        auto getName() {
            return Name;
        }
        auto getContact() {
            return Contact;
        }
      auto getAddress() {
          return Address;
      }
      User() = default;
};
std::ostream & operator<<(std::ostream &stream, const User &u)
{
    stream << u.Name << " " << u.Contact << " " << u.Address;
    return stream;
}
std::vector<User> findmatches( std::vector<User> &v, 
                           std::string Name, 
                           std::string Contact, 
                           std::string Address) {
    std::vector<User> matches;
    std::copy_if(v.begin(), v.end(), std::back_inserter(matches),
    [Name, Contact, Address](User& u)
    {
        return(u.getName() == Name 
        && u.getContact() == Contact 
        && u.getAddress() == Address);
    });
    return matches;
}

int main () {
std::vector<User> v {};
v.push_back({"Tom Cruise","917-032-2342","200 Top Gun Lane, Miramar, CA 93212"});
v.push_back({"Chuck Norris","911-032-1111","300 Santa Monica Blvd, Hollywood, CA 93212"});
v.push_back({"Santa Clause","315-4323-3111","1 North Pole Circle, North Pole, Elf Division, Antarctica 00000"});
auto matches = findmatches(v, "Chuck Norris", "911-032-1111", "300 Santa Monica Blvd, Hollywood, CA 93212");
for ( auto i : matches ) {
    std::cout << i << std::endl; 
  }
}

将静态变量转换为结构:

struct Search_conditions
{
    string name, contact, address;
    bool operator()(User& u) {...}
};
Search_conditions sc = {name, contact, address};
find_if(u.begin(), u.end(), sc);