我们可以得到一个迭代器来从 C++ 中的谓词过滤向量吗?
Can we get an iterator that filters a vector from a predicate in C++?
是否有可能获得一个向量迭代器,用谓词过滤某些元素,即显示向量的视图?
我觉得remove_if
做了类似的事情,但我还没有发现我是否可以随意使用它。
类似于:
auto it = filter(vec.begin(), vec.end(), predicate);
// I can reuse the iterator like:
for (auto i = it; i != vec.end(); i++)
// ...
编辑: (更多上下文以获得最佳答案) 我在一个 sqlite 数据库中做了很多查询记录数据以便打印报告。
由于需要的请求数量,目前性能不佳。我相信查询一次数据库并将结果存储在智能指针向量中(unique_ptr
如果可能),然后使用纯 C++ 查询向量可能会更快。
使用 copy_if
是进行查询的好方法,但我不需要复制所有内容,最后可能会花费太多(对此不确定),我应该提一下在我的例子中,数据是不可变的。
正如@Jarod42 在评论中提到的,一种解决方案是使用范围:
#include <algorithm>
#include <iostream>
#include <vector>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
int main()
{
std::vector<int> numbers = { 1, 2, 3 ,4, 5 };
auto predicate = [](int& n){ return n % 2 == 0; };
auto evenNumbers = numbers | ranges::view::filter(predicate);
auto result = numbers | ranges::view::filter(predicate)
| ranges::view::transform([](int n) { return n * 2; });
for (int n : evenNumbers)
{
std::cout << n << ' ';
}
std::cout << '\n';
for (int n : result)
{
std::cout << n << ' ';
}
}
evenNumbers
是一个范围视图适配器,它坚持 numbers
范围并改变它的迭代方式。
result
是在谓词上过滤并应用函数的数字范围。
查看编译
信用:fluentcpp
你的问题
Can we get an iterator that filters a vector from a predicate in C++?
在你被问到的意义上,只能回答:不。目前没有(C++17)。根据您的要求,迭代器然后必须存储谓词并检查位置的每次修改或所有取消引用的内容。即在任何取消引用之前,需要检查谓词。因为其他代码可能会修改您的 std::vector。迭代器需要一直检查谓词。开始、结束、距离等标准功能也会相当复杂。
因此您可以通过从现有迭代器派生来创建自己的迭代器。存储谓词并重载大部分函数来处理谓词。非常非常复杂,工作量很大,也许不是,你想要的东西。这将是准确获得您要求的功能的唯一方法。
对于解决方法,还有许多其他可能的解决方案。人们会在这里告诉你。
但是如果我读了你的陈述
"showing a view of the vector"
然后生活变得更轻松。正如 oblivion 所写,您可以通过使用 std::copy_if 有条件地复制它来轻松创建矢量视图。这是我认为最好的答案。它具有 none 破坏性。但它是快照而不是原始数据。所以,它是只读的。而且,它不考虑拍摄快照后对原始 std::vector 的更改。
第二个选项,std::remove_if和std::erase的组合,会破坏原始数据。或者更好地说,它会使过滤掉的数据无效。您也可以 std::copy_if 不需要的数据到备份区域, std::remove_if 它们,最后将它们再次添加到向量中。
所有这些方法都很关键,如果原始数据会被修改。
也许对您来说,标准 std::copy_if 最适合创建视图。然后,您将 return 复制的迭代器并使用它。
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> testVector{ 1,2,3,4,5,6,7 }; // Test data
std::vector<int> testVectorView{}; // The view
// Create predicate
auto predForEvenNumbers = [](const int& i) -> bool { return (i % 2 == 0); };
// And filter. Take a snapshot
std::copy_if(testVector.begin(), testVector.end(), std::back_inserter(testVectorView), predForEvenNumbers);
// Show example result
std::vector<int>::iterator iter = testVectorView.begin();
std::cout << *iter << '\n';
return 0;
}
请注意。对于大 std::vectors,它将成为一个非常昂贵的解决方案。 . .
是否有可能获得一个向量迭代器,用谓词过滤某些元素,即显示向量的视图?
我觉得remove_if
做了类似的事情,但我还没有发现我是否可以随意使用它。
类似于:
auto it = filter(vec.begin(), vec.end(), predicate);
// I can reuse the iterator like:
for (auto i = it; i != vec.end(); i++)
// ...
编辑: (更多上下文以获得最佳答案) 我在一个 sqlite 数据库中做了很多查询记录数据以便打印报告。
由于需要的请求数量,目前性能不佳。我相信查询一次数据库并将结果存储在智能指针向量中(unique_ptr
如果可能),然后使用纯 C++ 查询向量可能会更快。
使用 copy_if
是进行查询的好方法,但我不需要复制所有内容,最后可能会花费太多(对此不确定),我应该提一下在我的例子中,数据是不可变的。
正如@Jarod42 在评论中提到的,一种解决方案是使用范围:
#include <algorithm>
#include <iostream>
#include <vector>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
int main()
{
std::vector<int> numbers = { 1, 2, 3 ,4, 5 };
auto predicate = [](int& n){ return n % 2 == 0; };
auto evenNumbers = numbers | ranges::view::filter(predicate);
auto result = numbers | ranges::view::filter(predicate)
| ranges::view::transform([](int n) { return n * 2; });
for (int n : evenNumbers)
{
std::cout << n << ' ';
}
std::cout << '\n';
for (int n : result)
{
std::cout << n << ' ';
}
}
evenNumbers
是一个范围视图适配器,它坚持 numbers
范围并改变它的迭代方式。
result
是在谓词上过滤并应用函数的数字范围。
信用:fluentcpp
你的问题
Can we get an iterator that filters a vector from a predicate in C++?
在你被问到的意义上,只能回答:不。目前没有(C++17)。根据您的要求,迭代器然后必须存储谓词并检查位置的每次修改或所有取消引用的内容。即在任何取消引用之前,需要检查谓词。因为其他代码可能会修改您的 std::vector。迭代器需要一直检查谓词。开始、结束、距离等标准功能也会相当复杂。
因此您可以通过从现有迭代器派生来创建自己的迭代器。存储谓词并重载大部分函数来处理谓词。非常非常复杂,工作量很大,也许不是,你想要的东西。这将是准确获得您要求的功能的唯一方法。
对于解决方法,还有许多其他可能的解决方案。人们会在这里告诉你。
但是如果我读了你的陈述
"showing a view of the vector"
然后生活变得更轻松。正如 oblivion 所写,您可以通过使用 std::copy_if 有条件地复制它来轻松创建矢量视图。这是我认为最好的答案。它具有 none 破坏性。但它是快照而不是原始数据。所以,它是只读的。而且,它不考虑拍摄快照后对原始 std::vector 的更改。
第二个选项,std::remove_if和std::erase的组合,会破坏原始数据。或者更好地说,它会使过滤掉的数据无效。您也可以 std::copy_if 不需要的数据到备份区域, std::remove_if 它们,最后将它们再次添加到向量中。
所有这些方法都很关键,如果原始数据会被修改。
也许对您来说,标准 std::copy_if 最适合创建视图。然后,您将 return 复制的迭代器并使用它。
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> testVector{ 1,2,3,4,5,6,7 }; // Test data
std::vector<int> testVectorView{}; // The view
// Create predicate
auto predForEvenNumbers = [](const int& i) -> bool { return (i % 2 == 0); };
// And filter. Take a snapshot
std::copy_if(testVector.begin(), testVector.end(), std::back_inserter(testVectorView), predForEvenNumbers);
// Show example result
std::vector<int>::iterator iter = testVectorView.begin();
std::cout << *iter << '\n';
return 0;
}
请注意。对于大 std::vectors,它将成为一个非常昂贵的解决方案。 . .