我最终要遵循以下代码,以便从std :: vector中过滤掉一些不良元素:
#include <iostream>
#include <vector>
#include <algorithm>
typedef struct mystruct {
int id;
std::string name;
};
int main()
{
std::vector<mystruct> all_items = {{151, "test1"}, {154, "test4"}, {152, "test2"}, {151, "test1"}, {151, "test1"}, {153, "test3"}};
std::vector<int> bad_ids = {151, 152};
std::vector<mystruct> filter_items;
for (const auto& item : all_items) {
if ( std::find(bad_ids.begin(), bad_ids.end(), item.id) != bad_ids.end() ) {
std::cout << "id: " << item.id << " is bad" << std::endl;
} else {
std::cout << "id: " << item.id << " is good item" << std::endl;
filter_items.emplace_back(item);
}
}
for (auto f : filter_items) {
std::cout << "Good item: " << f.id << std::endl;
}
}
有没有更有效的方法?可以在这里使用std :: remove_copy_if或Boost吗?
答案 0 :(得分:5)
是的,您可以使用std::remove_copy_if,例如
std::remove_copy_if(
all_items.begin(),
all_items.end(),
std::back_inserter(filter_items),
[&bad_ids](const mystruct& item) { return std::find(bad_ids.begin(), bad_ids.end(), item.id) != bad_ids.end(); });
或者您可以直接在矢量上使用std::remove_if和erase 坏元素,例如
all_items.erase(
std::remove_if(
all_items.begin(),
all_items.end(),
[&bad_ids](const mystruct& item) { return std::find(bad_ids.begin(), bad_ids.end(), item.id) != bad_ids.end(); }),
all_items.end());
答案 1 :(得分:2)
扩展@ songyuanyao的正确答案,保留一个容器帮助程序库以使代码更具表现力永远不会伤害。
#include <iostream>
#include <vector>
#include <algorithm>
struct mystruct {
int id;
std::string name;
};
template<class T, class A, class Pred>
std::vector<T, A> copy_unless(std::vector<T, A> container, Pred&& pred)
{
container.erase(std::remove_if(container.begin(), container.end(),
std::forward<Pred>(pred)),
container.end());
return container;
}
template<class Container, class Pred>
bool any_match(Container&& container, Pred&& pred)
{
return std::find_if(container.begin(), container.end(), pred) != container.end();
}
int main()
{
std::vector<mystruct> all_items = {{151, "test1"}, {154, "test4"}, {152, "test2"}, {151, "test1"}, {151, "test1"}, {153, "test3"}};
std::vector<int> bad_ids = {151, 152};
auto is_bad = [&bad_ids](mystruct const& item)
{
auto match_id = [&item](int id){ return item.id == id; };
return any_match(bad_ids, match_id);
};
auto filter_items = copy_unless(all_items, is_bad);
for (auto&& f : filter_items) {
std::cout << "Good item: " << f.id << std::endl;
}
}
我确信我记得有一个这样的图书馆,但是对于我的生活,我不记得它是哪一个。
答案 2 :(得分:1)
我建议提升范围:
<强> Live On Coliru 强>
int main() {
myvec all_items = { { 151, "test1" }, { 154, "test4" }, { 152, "test2" },
{ 151, "test1" }, { 151, "test1" }, { 153, "test3" } };
auto is_good = [bad_ids = std::set<int> { 151, 152 }](mystruct v) {
return bad_ids.end() == bad_ids.find(v.id);
};
// just filter on the fly:
for (auto& f : all_items | filtered(is_good)) {
std::cout << "Good item: " << f.id << std::endl;
}
// actually copy:
auto filter_items = boost::copy_range<myvec>(all_items | filtered(is_good));
}
打印
Good item: 154
Good item: 153
你可以通过稍微分解一下来改善风格:
假设你有一个像contains
这样的实用程序:
template <typename... Arg, typename V> bool contains(std::set<Arg...> const &set, V const &v) {
return set.end() != set.find(v);
}
template <typename... Arg, typename V> bool contains(std::vector<Arg...> const &vec, V const &v) {
return vec.end() != std::find(vec.begin(), vec.end(), v);
}
然后它变得更具可读性:
<强> Live On Coliru 强>
auto is_good = [&bad_ids](auto& v) { return !contains(bad_ids, v.id); };
for (auto& f : all_items | filtered(is_good)) {
std::cout << "Good item: " << f.id << std::endl;
}
现在,我觉得整个bad_ids
列表可能也是动态的。但如果它不是,那么你就可以更多地“就地”#34;使用凤凰城:
<强> Live On Coliru 强>
for (auto& f : all_items | filtered(!contains_(std::set<int> { 151, 152 }, arg1->*&mystruct::id))) {
std::cout << "Good item: " << f.id << std::endl;
}
我知道。他没有任何理由推动它,但是嘿。只是显示:)
答案 3 :(得分:0)
为什么不使用partition
算法?它将重新安排all_items
,以便首先放置好的物品,然后放置不好。