像python的 'groupby'这样的C++算法

标签 c++ boost stl c++11 containers

是否有任何类似于 itertools.groupby() 的 C++ 转换? ?

当然,我可以轻松编写自己的代码,但我更喜欢利用惯用行为,或者根据 STL 或 boost 提供的功能编写一个。

#include <cstdlib>
#include <map>
#include <algorithm>
#include <string>
#include <vector>

struct foo
{
        int x;
        std::string y;
        float z;
};

bool lt_by_x(const foo &a, const foo &b)
{
        return a.x < b.x;
}

void list_by_x(const std::vector<foo> &foos, std::map<int, std::vector<foo> > &foos_by_x)
{
        /* ideas..? */
}

int main(int argc, const char *argv[])
{
        std::vector<foo> foos;
        std::map<int, std::vector<foo> > foos_by_x;

        std::vector<foo> sorted_foos;
        std::sort(foos.begin(), foos.end(), lt_by_x);
        list_by_x(sorted_foos, foos_by_x);

        return EXIT_SUCCESS;
}

最佳答案

这并不能真正回答您的问题,但为了好玩,我实现了一个 group_by 迭代器。也许有人会觉得它有用:

#include <assert.h>
#include <iostream>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using std::cout;
using std::cerr;
using std::multiset;
using std::ostringstream;
using std::pair;
using std::vector;

struct Foo
{
  int x;
  std::string y;
  float z;
};

struct FooX {
  typedef int value_type;
  value_type operator()(const Foo &f) const { return f.x; }
};



template <typename Iterator,typename KeyFunc>
struct GroupBy {
  typedef typename KeyFunc::value_type KeyValue;

  struct Range {
    Range(Iterator begin,Iterator end)
    : iter_pair(begin,end)
    {
    }

    Iterator begin() const { return iter_pair.first; }
    Iterator end() const { return iter_pair.second; }

    private:
      pair<Iterator,Iterator> iter_pair;
  };

  struct Group {
    KeyValue value;
    Range range;

    Group(KeyValue value,Range range)
    : value(value), range(range)
    {
    }
  };


  struct GroupIterator {
    typedef Group value_type;

    GroupIterator(Iterator iter,Iterator end,KeyFunc key_func)
    : range_begin(iter), range_end(iter), end(end), key_func(key_func)
    {
      advance_range_end();
    }

    bool operator==(const GroupIterator &that) const
    {
      return range_begin==that.range_begin;
    }

    bool operator!=(const GroupIterator &that) const
    {
      return !(*this==that);
    }

    GroupIterator operator++()
    {
      range_begin = range_end;
      advance_range_end();
      return *this;
    }

    value_type operator*() const
    {
      return value_type(key_func(*range_begin),Range(range_begin,range_end));
    }


    private:
      void advance_range_end()
      {
        if (range_end!=end) {
          typename KeyFunc::value_type value = key_func(*range_end++);
          while (range_end!=end && key_func(*range_end)==value) {
            ++range_end;
          }
        }
      }

      Iterator range_begin;
      Iterator range_end;
      Iterator end;
      KeyFunc key_func;
  };

  GroupBy(Iterator begin_iter,Iterator end_iter,KeyFunc key_func)
  : begin_iter(begin_iter),
    end_iter(end_iter),
    key_func(key_func)
  {
  }

  GroupIterator begin() { return GroupIterator(begin_iter,end_iter,key_func); }

  GroupIterator end() { return GroupIterator(end_iter,end_iter,key_func); }

  private:
    Iterator begin_iter;
    Iterator end_iter;
    KeyFunc key_func;
};


template <typename Iterator,typename KeyFunc>
inline GroupBy<Iterator,KeyFunc>
  group_by(
    Iterator begin,
    Iterator end,
    const KeyFunc &key_func = KeyFunc()
  )
{
  return GroupBy<Iterator,KeyFunc>(begin,end,key_func);
}


static void test()
{
  vector<Foo> foos;
  foos.push_back({5,"bill",2.1});
  foos.push_back({5,"rick",3.7});
  foos.push_back({3,"tom",2.5});
  foos.push_back({7,"joe",3.4});
  foos.push_back({5,"bob",7.2});

  ostringstream out;

  for (auto group : group_by(foos.begin(),foos.end(),FooX())) {
    out << group.value << ":";
    for (auto elem : group.range) {
      out << " " << elem.y;
    }
    out << "\n";
  }

  assert(out.str()==
    "5: bill rick\n"
    "3: tom\n"
    "7: joe\n"
    "5: bob\n"
  );
}

int main(int argc,char **argv)
{
  test();
  return 0;
}

关于像python的 'groupby'这样的C++算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12335860/

相关文章:

c++ - 如何将 boost 回调作为参数传递给方法?

c++ - 尝试使用 boost::interprocess::managed_shared_memory::construct<T> 编译应用程序时出错

c++ - 在 std 命名空间中添加模板特化

C++ 模板函数。错误 C2440 : 'return' : cannot convert from '_FwdIt1' to '_FwdIt1'

c++ - 将抽象类实现为其他类的接口(interface)而无需 vtable 开销

c++ - Boost库文件生成

c++ - 在 C++ 中读取字节

c++ - 如何使用 (lambda) 函数填充 C++ 容器?

c++ - 无法通过进位传播值(value)

c++ - 我应该使用哪种数据类型在 C++ 的变量中存储最多 18 位数字?