【问题标题】:How to fold STL container?如何折叠 STL 容器?
【发布时间】:2011-04-23 20:04:27
【问题描述】:

我需要一个类似 Haskell 的 foldl 函数来折叠任何 STL 容器。预期签名如下:

template Iterator, FoldingFunction, Result
Result foldl(
  Iterator begin, 
  Iterator end, 
  FoldingFunction f, 
  Result initValue);

标准 STL 没有这样的功能。 Boost有吗?

我知道实现起来很简单,但我想知道是否有现成的标准化实现。

还有一个问题:您通常如何在 C++/STL 中折叠数据列表?

【问题讨论】:

  • 你所说的“折叠”到底是什么意思??
  • @Konrad: fold = 减少 = 累积。
  • @Konrad - 以某种顺序处理数据结构并构建返回值。 haskell.org/haskellwiki/Fold

标签: c++ boost stl fold


【解决方案1】:

STL 确实有这样的功能:std::accumulate。但是,它在标头中<numeric>,而不是<algorithm>

实际上Wikipedia page on "Fold" 已经列出了大多数编程语言(包括 C++)上的foldl/foldr 函数。

【讨论】:

  • 请注意,accumulate 使用 value_type 的迭代器参数作为内部累加器变量,尽管接受和返回不同的类型,并允许其他类型仍在仿函数参数中。
  • @Potatoswatter:我没有从累积定义中看到这个:TYPE 累积(input_iterator start, input_iterator end, TYPE val, BinaryFunction f);
  • @Andrey:没关系。我在考虑缺陷报告 539 (open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#539)。 accumulate 使用正确的内部类型。
  • 顺便说一句,accumulate 是左折叠;认为 (1 + 2) + 3 而不是 1 + (2 + 3);就像 Haskell 中的 foldl
  • @user:对foldr使用反向迭代器。
【解决方案2】:

您是否查看过<numeric> 标头中的std::accumulate

【讨论】:

  • 它是std::accumulate。它在 std 命名空间中,但在 <numeric> 标头中。 :)
  • @jalf 让他们继续前进。只有这样我才能排队。 :P
【解决方案3】:

这是我使用 std::accumulate 的实现

template<typename collection, typename operation>
typename collection::value_type reduce(collection col, operation op)
{
    return accumulate(col.begin(),  col.end(), typename collection::value_type(), op);
}

reduce 在 Haskell 中表示折叠。而且这个函数模板可以让程序更实用:)

【讨论】:

  • 使用begin(col)end(col) 会更通用,但这个函数仍然是相当多余的,因为accumulate 也很容易直接调用。
【解决方案4】:

虽然std:: accumulate 似乎是最好的候选人,但我认为使用旧的for_each 也可以达到要求。

我从answer of KennyTM中的链接中提取示例,并翻译了所有示例 到for_eachThe full code is posted at codepad,以下是部分摘录:

struct result_functor {
    result_functor( int initial, int multiplier ) :
        result_( initial ), multiplier_( multiplier ) {
    }
    int operator()( int x ) {
        result_ += multiplier_ * x;
        return result_;
    }
    int result_;
    int multiplier_;
};

const int init = 100;
const int numbers[] = { 10, 20, 30 };

const int accum_sum = std::accumulate( numbers, numbers + 3, init );
const result_functor for_sum = for_each( 
    numbers, numbers + 3, result_functor( init, +1 ) );
assert( accum_sum == for_sum.result_ );

【讨论】:

  • 有状态函子 result_functor 表示未定义的行为。
  • @Loom 这个答案表明有状态函子适用于std::for_eachstackoverflow.com/a/6113053/2348315,是不是不正确?
【解决方案5】:

为什么不只是;

b_t foldl(b_t (*f)(b_t,a_t),b_t base_case,a_t * in_list){
 int l = sizeof(inList)/sizeof(a_t);
 b_t carry = base_case;
 for(int i = 0;i<l;i++){
   carry = f(carry,in_list[i]);
  }
 return carry;
}

或递归; // 也许你可以帮助我正确的语法...

b_t foldl(b_t (*f)(b_t,a_t),b_t base_case,a_t * in_list){
 return foldl(f,f(base_case,in_list[0]),in_list + 1);      
}

【讨论】:

  • 因为这仅适用于 b_ta_t 和函数指针。此外,与标准库实现中可以找到的更广泛使用和测试的替代方案相比,它的可信度更低。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-24
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 2019-02-12
  • 2010-09-27
  • 1970-01-01
相关资源
最近更新 更多