简体   繁体   English

是否存在std中的折叠类似算法(或者失败:boost)?

[英]Is there a fold like algorithm in std (or failing that: boost) available?

A very simpel example is multiplication - suppose I have a vector: 一个非常简单的例子是乘法 - 假设我有一个向量:

std::vector<int> ints = {1,2,3,4};

With a naive approach I can just use std::accumulate (or std::reduce ) and it looks like this: 使用简单的方法我可以使用std::accumulate (或std::reduce ),它看起来像这样:

int result = std::accumulate(ints.begin(), ints.end(), int{}, [](const int &a, const int &b){return a*b;});

but since the initial value is zero - the result becomes zero as well (For this specific case, one way I could fix it is by putting a '1' as initial). 但由于初始值为零 - 结果也变为零(对于这种特定情况,我可以解决的一种方法是将'1'作为初始值)。

I would rather use an algorithm that does the above but without an initial value 'side-effect' (ie. just multiply the numbers in vector). 我宁愿使用一种算法来完成上述操作但没有初始值'副作用'(即只是乘以向量中的数字)。

A similar problem is often encountered within string handling where a delimiter must be inserted between elements. 在字符串处理中经常遇到类似的问题,其中必须元素之间插入分隔符。

What you're talking about can be reframed as a generalisation of accumulate over the last N-1 elements of your range, with the 1st element being the initial value. 你所谈论的内容可以被重新定义为在你的范围的最后N-1个元素上accumulate的概括,第一个元素是初始值。

So you can just write: 所以你可以写:

std::accumulate(std::next(std::begin(ints)), std::end(ints), *std::begin(ints), OP);

You have to assume that ints is non-empty, though, which raises my main point: what should a hypothetical standard function return when the range is empty? 你必须假设ints是非空的,这提出了我的要点:当范围为空时,假设的标准函数应该返回什么? Should its results simply be undefined? 它的结果应该是不确定的吗? Is that sensible? 那是明智的吗?

Accumulate sidesteps this issue and provides a boatload of flexibility, by doing things the way it does. 积累回避这个问题,通过按照它的方式做事提供了大量的灵活性。 I think that's a good thing. 我认为这是件好事。

Combined with the ability to simply provide an appropriate initial value like 1 for your operation over the whole range, I'm not convinced there's much need for this hypothetical alternative in the standard. 结合在整个范围内为您的操作简单地提供适当的初始值(如1的能力,我不相信标准中需要这个假设的替代方案。

It might also be difficult to come up with two names for it that mirror the already-asymmetrically-named "accumulate" and "reduce". 也许很难为它提出两个名称来反映已经非对称命名的“累积”和“减少”。


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));
}

…or something like that anyway. ......或者类似的东西。 Note that this necessarily copies the first element; 请注意,这必然会复制第一个元素; you could avoid that if you weren't lazy by calling into std::accumulate like I did. 你可以避免这种情况,如果你不是像我一样调用std::accumulate而不是懒惰。 😊 😊

In addition to @Lightness Races in Orbit's answer, consider the case in Haskell: For cases like you described it (most prominently searching the maximum element in a list), Haskell delivers the functions foldl1 and foldr1 , which perform the fold over the collection and implicitly taking the first value as initial value. 除了Orbit答案中的@Lightness Races之外,还要考虑Haskell中的情况:对于像你描述的那样(最突出地搜索列表中的最大元素),Haskell提供了foldl1foldr1函数,它们对集合执行折叠,隐含地将第一个值作为初始值。 Yes, for the empty list this makes no sense, hence for this problem you have to provide a list with at least one element. 是的,对于空列表,这没有任何意义,因此对于此问题,您必须提供至少包含一个元素的列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM