标准中是否有类似折叠的算法(或失败:提升)可用?
Is there a fold like algorithm in std (or failing that: boost) available?
一个非常简单的例子是乘法 - 假设我有一个向量:
std::vector<int> ints = {1,2,3,4};
使用天真的方法,我可以使用std::accumulate
(或std::reduce
(,它看起来像这样:
int result = std::accumulate(ints.begin(), ints.end(), int{}, [](const int &a, const int &b){return a*b;});
但由于初始值为零 - 结果也变为零(对于这种特定情况,我可以修复它的一种方法是将"1"作为初始(。
我宁愿使用一种算法来执行上述操作,但没有初始值"副作用"(即只需将向量中的数字相乘(。
在字符串处理中经常遇到类似的问题,其中必须在元素之间插入分隔符。
您所说的可以重新构建为范围的最后N-1个元素的accumulate
的概括,第一个元素是初始值。
所以你可以写:
std::accumulate(std::next(std::begin(ints)), std::end(ints), *std::begin(ints), OP);
但是,您必须假设ints
是非空的,这提出了我的主要观点:当范围为空时,假设的标准函数应该返回什么?它的结果是否应该只是不确定的?这合理吗?
(当前草案(
237)
accumulate
类似于 APL 归约运算符和 Common Lisp 归约函数,但它避免了在空序列上定义归约结果的困难,因为它总是要求一个初始值
积累回避了这个问题,并通过按它的方式做事提供了大量的灵活性。我认为这是一件好事。
结合能够简单地为您的整个范围内的操作提供适当的初始值(如1
(,我不相信标准中需要这种假设的替代方案。
可能也很难为它想出两个名字来反映已经不对称命名的"积累"和"减少"。
template <class InputIt, class T, class BinaryOperation>
T fold_if_you_really_want_to(InputIt first, InputIt last, BinaryOperation op)
{
// UB if range is empty. Whatevs.
T init = *first;
return std::accumulate(++first, last, std::move(init), std::move(op));
}
无论如何,或者类似的东西。请注意,这必然复制第一个元素;如果你不像我一样懒惰,你可以通过打电话给std::accumulate
来避免这种情况。
除了@Lightness Races in Orbit的答案之外,考虑一下Haskell的情况: 对于像你描述的情况(最突出的是搜索列表中的最大元素(,Haskell提供了函数foldl1
和foldr1
,它们在集合上执行折叠,并隐式地将第一个值作为初始值。 是的,对于空列表,这毫无意义,因此对于此问题,您必须提供一个至少包含一个元素的列表。
- 提升 1.64 单元测试编译失败
- 使用提升库构建失败
- 使用自定义访问者时具有自定义类型的提升变体失败(源自 boost::static_visitor)
- 访问提升:shared_ptr 主范围外崩溃,断言失败:px != 0.指针的正确用法是什么?
- 使用提升线程时编译失败
- 提升继续恢复断言失败
- 从 std::vector<double> 到 Python 列表的转换失败(提升 python)
- 使用提升对字符串进行标记化时,将令牌转换为 char* const* 时失败
- 提升精神模板专业化失败
- 标准中是否有类似折叠的算法(或失败:提升)可用?
- 建筑物提升失败检查子模块/上下文
- C++ 提升 UDP 接收器在放入线程时失败
- 使用分位数函数提升断言失败的消息
- 由于管道破裂,提升 asio 发送消息失败
- 提升 XML 序列化在编译期间失败
- 提升 Python 导入失败,未定义包装类的符号
- 提升单元测试不会失败
- Qt 窗口包含提升线程标头失败
- 提升线程链接在 Netbeans 7.1 调试/测试会话中失败
- 语法意外失败提升::精神语法定义