我有一个struct
,其中包含姓名和号码:
struct S {
string name;
int number;
};
S
的对象存储在向量中。矢量基于name
排序。可能有多个项目具有相同的name
。
当迭代向量中的项目时,我正在尝试使用count_if
来检测重复项:
for(size_t i = 0; i < v.size(); ++i)
{
const S& s = v[i];
int count = count_if(v.begin(), v.end(), XXX);
// do something with count
}
在上面,我无法弄清楚XXX应该是什么。我试图创建一个谓词,但它没有用,因为没有什么可比较的:
bool IsEqualName(const S& s) {
return s.name == ???;
}
我找到的文件leaves a lot to be desired。
我觉得我错过了一些非常明显的东西,但我看不出它是什么。有谁可以指出我的错误?
杰夫
答案 0 :(得分:5)
可以写一个仿函数来实现这个目标:
struct FindName
{
FindName(const std::string& name) : name_(name) {}
bool operator()(const S& s) { return s.name == name_; }
private:
std::string name_;
};
int count = count_if(v.begin(), v.end(), FindName("noloader"));
如果您使用的是C ++ 11,请使用lambda:
int count = count_if(v.begin(), v.end(),
[](const S& s){ return s.name == "noloader"; });
答案 1 :(得分:1)
由于您的商品已排序,因此您可以比find_if做得更好。在这种情况下,std::upper_bound
应该可以很好地工作。
由于您基于S
name
的顺序,因此最简单的方法是重载operator<
来执行此操作:
struct S {
string name;
int number;
bool operator<(S const &other) { return name < other.name; }
};
[顺便说一句,您可以在排序时使用它,如sort(v.begin(), v.end());
]
要查找每个项目出现的次数,请从v.begin()开始,并使用std::upper_bound
查找与第一项相等的项的上限,然后更新您正在查找的范围的开头到了刚刚返回的迭代器upper_bound
,并重复直到你到达集合的末尾:
std::vector<size_t> counts;
auto pos = v.begin();
for (auto prev=v.begin(); prev != v.end(); prev = pos) {
pos = std::upper_bound(prev, v.end(), *prev);
counts.push_back(pos - prev);
}
如果你有很多重复项,这至少有可能更快一些 - 或者如果你真的有很多重复项要快得多(upper_bound
是对数的,find_if
是线性)。