如何用更清晰的STL算法替代嵌套循环查找两个vector匹配元素
问题描述
给定如下C++结构体定义和两个vector:
struct bob { int a {1}; std::string b{"bob"}; }; std::vector<bob> list1{{1, "a"}, {2, "b"}, {3, "c"}}; std::vector<bob> list2{{1, "x"}, {2, "b"}, {3, "x"}};
需要判断两个vector中是否存在成员a和b均相等的匹配元素。
最初采用嵌套循环实现:
for (const auto &item1 : list1) { for (const auto &item2 : list2) { std::cout << "loop check: " << item1.a << "," << item1.b << " == "<< item2.a << "," << item2.b << "\n"; if (item2.a == item1.a && item2.b == item1.b) { return true; } } }
但clang-tidy提示不应使用原生循环,于是改用std::any_of实现:
return std::any_of( list1.begin(), list1.end(), [&](const auto &item1) { return std::any_of( list2.begin(), list2.end(), [&](const auto &item2) { std::cout << "stl check: " << item1.a << "," << item1.b << " == "<< item2.a << "," << item2.b << "\n"; return item2.a == item1.a && item2.b == item1.b; }); });
但这个实现可读性差且冗余,请问是否有更清晰、表达性更强的算法或实现方式?(使用C++17标准)
优化实现方案
1. 为结构体重载==运算符
先把bob对象的相等判断逻辑封装起来,避免重复编写成员比较代码:
struct bob { int a {1}; std::string b{"bob"}; bool operator==(const bob& other) const noexcept { return a == other.a && b == other.b; } };
2. 简化STL算法组合写法
基于重载的==,用std::find替代内层的std::any_of,语义更直观:
return std::any_of(list1.cbegin(), list1.cend(), [&](const auto& item1) { std::cout << "checking: " << item1.a << "," << item1.b << "\n"; return std::find(list2.cbegin(), list2.cend(), item1) != list2.cend(); });
std::find的语义明确是“查找匹配元素”,相比嵌套any_of,可读性大幅提升。
3. 大数据量场景:哈希集合优化性能
如果vector元素数量较多,嵌套遍历的O(n*m)复杂度会成为瓶颈。可以先将其中一个vector的元素存入哈希集合,再遍历另一个vector查找,将复杂度降到O(n+m):
// 自定义bob的哈希函数 struct BobHash { size_t operator()(const bob& obj) const noexcept { size_t hash1 = std::hash<int>{}(obj.a); size_t hash2 = std::hash<std::string>{}(obj.b); return hash1 ^ (hash2 << 1); // 简单组合哈希值,也可采用更稳健的合并方式 } }; // 构建集合并查找 std::unordered_set<bob, BobHash> set2(list2.cbegin(), list2.cend()); return std::any_of(list1.cbegin(), list1.cend(), [&](const auto& item1) { std::cout << "checking: " << item1.a << "," << item1.b << "\n"; return set2.find(item1) != set2.end(); // C++17写法,C++20可改用set2.contains(item1) });
4. 抽离命名函数强化可读性
如果需要更明确的语义,可以把判断逻辑抽成命名函数:
bool isPresentInList(const bob& item, const std::vector<bob>& targetList) { std::cout << "checking: " << item.a << "," << item.b << "\n"; return std::find(targetList.cbegin(), targetList.cend(), item) != targetList.cend(); } // 调用时 return std::any_of(list1.cbegin(), list1.cend(), [&](const auto& item) { return isPresentInList(item, list2); });
函数名直接表达逻辑意图,代码可读性进一步提升。
内容的提问来源于stack exchange,提问作者code_fodder
相关产品推荐
相关产品推荐

