c++收集算法
C++ collect algorithm?
每隔一段时间,我需要迭代容器元素的一个子集,或者只是想提取它们并忽略其余部分。我最终使用boost::range::adaptors::filtered
来创建这个惰性集合。
for(auto&& i : container | filtered(predicate)) {
// .. do stuff
}
是否有理由在STL中缺乏收集算法(如Ruby的collect)(我们只有copy_if,这是不一样的)?或者有什么理由反对使用它吗?
一个可能的实现是:
template<class Container, class Predicate>
Container collect(Container&& c, Predicate&& p) {
Container n;
for(auto&& i : c) {
if(p(i)) {
n.push_back(i);
}
}
return n;
}
,但lazy_collect
也可能有助于避免复制。
下面所有的答案都很好。我真希望我能把它们都标记出来。我不知道std::back_inserter
。现在收集东西就像这样简单:
boost::copy( orig | filtered(predicate), std::back_inserter(collection));
标准算法不能直接操作容器(创建或销毁容器,或改变容器的大小)。它们对迭代器范围进行操作,算法所做的唯一改变是通过迭代器赋值。
所以,你提议的操作完全超出了标准算法的范围。也许标准中"应该"有大量额外的泛型容器操作集,包括这个,但是"STL哲学"是在迭代器上操作。
您建议的非延迟操作可以使用std::back_inserter
和std::copy_if
(可选择使用移动迭代器)或move_if
(如果您自己滚动)完成。C++03中缺少std::copy_if
,但这是一个偶然的疏忽。
惰性版本不能仅仅通过将标准组件连接在一起来完成——没有一种干净的方法可以在没有中间存储的情况下将一种算法的"输出"直接链接到另一种算法的"输入"。这就是为什么Boost提供了如此有趣的各种迭代器,以及range。
我不知道为什么它们没有被合并到c++ 11中,但是关于c++ 11有一点需要注意,那就是它太迟了。提案因为缺乏时间而被放弃,所以原因可能很简单,"考虑到已知的现有工作量,它从未被认为重要到足以提出建议"。
考虑到您的特定实现,并非所有容器都有push_back
,因此您可能不应该使用Container
作为模板参数名。PushBackSequence
将更能描述需求。
这个怎么样:
#include <algorithm>
#include <iterator>
std::copy_if(container.begin(), container.end(), std::back_inserter(result), []{...})
其中container
为要收集的容器,result
为存储收集的容器
从注释中:
当使用copy_if时,你需要事先知道你需要多少空间
那不是真的。您可以使用std::copy_if
与反向插入器:
#include <algorithm> // For std::copy_if
#include <iterator> // For std::back_inserter
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v(10);
std::iota(begin(v), end(v), 0); // Fills the vector with 0..9
std::vector<int> out;
std::copy_if(begin(v), end(v), back_inserter(out), [] (int x)
// ^^^^^^^^^^^^^^^^^^
{
return x > 4;
});
for (auto x : out) { std::cout << x << " "; }
}
下面是一个实例。
如果你想要一个直接作用于容器的函数,而不是作用于一对迭代器定义的范围,你可以写下面的帮助:
template<typename C1, typename C2, typename P>
void cont_copy_if(C1&& src, C2&& dst, P&& p)
{
std::copy_if(
begin(std::forward<C1>(src)),
end(std::forward<C1>(src)),
back_inserter(std::forward<C2>(dst)),
std::forward<P>(p)
);
}
你可以这样使用:
int main()
{
std::vector<int> v(10);
std::iota(begin(v), end(v), 0);
std::list<int> out;
// ^^^^^^^^^
// You could use a different destination container
cont_copy_if(v, out, [] (int x) { return x > 4; });
// ^^^^^^^^^^^^
for (auto x : out) { std::cout << x << " "; }
}
当然还有实际的例子
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 基于ELO的团队匹配算法
- C++选择排序算法中的逻辑错误
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- C++A*算法并不总是在路径中具有目标节点
- 排序算法c++
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- 算法问题:查找从堆栈中弹出的所有序列
- 下面是排序算法O(n)吗
- KMP算法和LPS表构造的运行时间
- 为什么我的排序算法会更改数组值
- 求最大元素位置的分治算法
- 具有非整数边容量的最大流量的Dinic算法
- 到连接组件算法的问题(递归)
- STL算法函数在多个一维容器上的使用
- 读取最后一行代码算法 - c++ 时出现问题
- 括号更改 O(n) 算法
- std::unordered_map 搜索算法是如何实现的?
- 如何实现高效的算法来计算大型数据集的多个不同值?
- 如何在 Mac 上使用 c++17 并行标准库算法?