C ++ Как заставить find_if возвращать не только первый объект, для которого верно применение pred к нему - PullRequest
2 голосов
/ 27 января 2012

Это позволяет пользователю вводить имя, контакт и адрес, которые он / она желает найти.Я хотел показать все объекты, для которых применяется 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;
}

Ответы [ 7 ]

10 голосов
/ 27 января 2012

Обычным решением является использование 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)
  }
} 
5 голосов
/ 27 января 2012

Псевдокод:

for(iterator i = v.begin(); 
    (i = find_if(i, v.end(), ...)) != v.end(); ++i )
{
    print *i;
}
3 голосов
/ 27 января 2012

Одним из методов будет использование std::copy_if (начиная с C ++ 11) или std::remove_copy_if путем отрицания вашего предиката с помощью not1 - этот copy_if обходной путь, который я нашел в ответе на вопрос «Почему существуетнет алгоритма std :: 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, наконец) таким образом, что все элементы, для которых предикат p возвращает истину, предшествуют элементам, для которых предикат p возвращает ложь. (http://en.cppreference.com/w/cpp/algorithm/partition)

std::vector<User>::const_iterator newend =
    std::partition(u.begin(), u.end(), search_User);
1 голос
/ 27 января 2012

(Требуется C ++ 11) Небольшое отклонение от предложенного MSalters будет записывать в 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();
             });

EDIT:

Чтобы отобразить сообщение «Пользователь не найден», вы можете изменить его следующим образом:

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 found\n";
0 голосов
/ 03 октября 2016

Для 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;
}

В настоящее время самое популярное решение @MSalters содержит ошибку в лямбде, в которой отсутствует оператор возврата.

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; 
  }
}
0 голосов
/ 27 января 2012

Чтобы преобразовать статические переменные в структуру:

struct Search_conditions
{
    string name, contact, address;

    bool operator()(User& u) {...}
};

Search_conditions sc = {name, contact, address};
find_if(u.begin(), u.end(), sc);
0 голосов
/ 27 января 2012

Вы можете пройтись по всем попаданиям, увеличив значение возврата в 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...