【问题标题】:Search for a struct item in a vector by member data通过成员数据在向量中搜索结构项
【发布时间】:2013-01-08 23:36:53
【问题描述】:

我对 c++ 很陌生,我正在尝试找到一种方法来搜索结构向量以查找具有特定成员数据的结构。

我知道这适用于向量中的简单类型

std::find(vector.begin(), vector.end(), item) != vector.end()

但是假设我有一个这样的结构:

struct Friend
{
  string name;
  string number;
  string ID;
};

还有一个像这样的向量:

vector<Friend> friends;

然后向量被朋友填充。

假设我想搜索具有特定 ID 的朋友,并找出详细信息。或者从向量中删除某个结构。有没有简单的方法来做到这一点?

【问题讨论】:

    标签: c++ algorithm std


    【解决方案1】:

    这可以通过std::find_if 和一个搜索谓词来完成,如果你有可用的 C++11(或 C++0x),它可以表示为一个 lambda 函数:

    auto pred = [](const Friend & item) {
        return item.ID == 42;
    };
    std::find_if(std::begin(friends), std::end(friends), pred) != std::end(friends);
    

    要将给定的 ID 作为变量使用,您必须在 lambda 表达式中捕获它(在 [...] 内):

    auto pred = [id](const Friend & item) {
        return item.ID == id;
    };
    std::find_if(std::begin(friends), std::end(friends), pred) != std::end(friends);
    

    如果没有可用的 C++11,则必须将谓词定义为仿函数(函数对象)。 Remy Lebeau's answer 使用这种方法。

    要删除与谓词定义的条件匹配的元素,请使用remove_if 而不是find_if(其余语法相同)。

    更多算法见the STL &lt;algorithm&gt; reference

    【讨论】:

    • auto 的用法很好!
    • @DanDan 是的,有时我不想直接定义 lambda,它被用作函数的参数(它使行很长)
    • 为什么第一个用.begin(),第二个用std::begin
    • @MooingDuck 谢谢,这是一个错误。我将它从一个更改为另一个,因此它与原始数组兼容。
    • @leemes 这也是我对 lambdas 的抱怨,但我从没想过这样做。这是个好主意!
    【解决方案2】:

    使用std::find_if()。 @leemes 和 @AndyProwl 向您展示了如何在 C++11 编译器中使用它。但是如果你没有使用 C++11 编译器,那么你可以像这样使用它,它定义了一个仿函数,将给定项目的 ID 与其构造函数中先前指定的 ID 进行比较:

    class MatchesID
    {
        std::string _ID;
    
    public:
        MatchesID(const std::string &ID) : _ID(ID) {}
    
        bool operator()(const Friend &item) const
        {
            return item.ID == _ID;
        }
    };
    
    std::find_if(vector.begin(), vector.end(), MatchesID("TheIDHere")) != vector.end();
    

    如果您的项目中有其他使用 ID 的类,您可以将此仿函数模板化:

    template<typename IDType>
    class MatchesID
    {
        IDType _ID;
    
    public:
        MatchesID(const IDType &ID) : _ID(ID) {}
    
        template<class ItemType>
        bool operator()(const ItemType &item) const
        {
            return item.ID == _ID;
        }
    };
    
    std::find_if(vector.begin(), vector.end(), MatchesID<std::string>("TheIDHere")) != vector.end();
    

    【讨论】:

    • 我把你的函子变成了通用的,所以它可以和其他类型一起使用。
    • @leemes:如果你采用这种方法,那么我建议也为 ID 的数据类型使用模板。
    【解决方案3】:

    您可以将 std::find_if 与仿函数(如果您使用 C++98)或 lambda(如果您使用 C++11,我会假设)结合使用:

    using namespace std;
    int ID = 3; // Let's say...
    auto it = find_if(begin(vector), end(vector), [=] (Friend const& f) { 
        return (f.ID == ID); 
        });
    bool found = (it != end(vector));
    

    【讨论】:

      【解决方案4】:

      如果要在 STL 容器中查找元素,请使用 std::findstd::find_if 算法 使用 C++03,您需要为 std::find 重载 operator==

      bool operator==(const Friend& lhs, const Friend& rhs)
      {
        return lhs.ID == rhs.ID;
      }
      
      if (std::find(friends.begin(), friends.end(), item) != friends.end())
      {
         // find your friend
      }
      

      或 C++11 与 lambda:

      std::find_if(friends.begin(), friends.end(),  [](Friend& f){ return f.ID == "1"; } );
      

      如果要删除某个元素,请使用std::remove_if

      std::remove_if(friends.begin(), friends.end(), 
            [](Friend& f){ return f.ID == "1"; });
      

      【讨论】:

      • 这样您就不会将逻辑保留在本地。 Friend 实例的相等性定义在其他一些场景中可能会有所不同。只是说......(应该没问题,因为无论如何ID都应该是唯一的)
      • 是的,这就是 C++11 的美化效果
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-17
      • 2020-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多