16

に似た C++ 変換はありitertools.groupby()ますか?

もちろん、自分で簡単に作成することもできますが、慣用的な動作を利用するか、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;
}
4

7 に答える 7

7

Eric Niebler のrange ライブラリは、group_byビューを提供します。

ドキュメントによると、これはヘッダーのみのライブラリであり、簡単に含めることができます。

標準の C++ スペースに入るはずですが、最近の C++11 コンパイラで使用できます。

最小限の作業例:

#include <map>
#include <vector>
#include <range/v3/all.hpp>
using namespace std;
using namespace ranges;

int main(int argc, char **argv) {
    vector<int> l { 0,1,2,3,6,5,4,7,8,9 };
    ranges::v3::sort(l);
    auto x = l | view::group_by([](int x, int y) { return x / 5 == y / 5; });
    map<int, vector<int>> res;

    auto i = x.begin();
    auto e = x.end();
    for (;i != e; ++i) {
      auto first = *((*i).begin());
      res[first / 5] = to_vector(*i);
    }

    // res = { 0 : [0,1,2,3,4], 1: [5,6,7,8,9] }
}

(これをclang 3.9.0でコンパイルしました。および--std=c++11

于 2016-05-21T11:50:49.240 に答える
6

私は最近発見しcppitertoolsました。

説明どおりに、このニーズを正確に満たします。

https://github.com/ryanhaining/cppitertools#groupby

于 2014-12-20T20:33:25.867 に答える
3

1行のコードであるアルゴリズムで標準C++ライブラリを肥大化させるポイントは何ですか?

for (const auto & foo : foos) foos_by_x[foo.x].push_back(foo);

また、 を見てstd::multimapください。それはまさにあなたが必要としているものかもしれません。

アップデート:

私が提供したワンライナーは、ベクトルが既にソートされている場合に最適化されていません。以前に挿入されたオブジェクトの反復子を覚えていれば、マップ検索の回数を減らすことができるため、次のオブジェクトの「キー」であり、キーが変更されている場合にのみ検索を行います。例えば:

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

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

class optimized_inserter {
  public:
    typedef std::map<int, std::vector<foo> > map_type;

    optimized_inserter(map_type & map) : map(&map), it(map.end()) {}

    void operator()(const foo & obj) {
        typedef map_type::value_type value_type;
        if (it != map->end() && last_x == obj.x) {
            it->second.push_back(obj);
            return;
        }
        last_x = obj.x;
        it = map->insert(value_type(obj.x, std::vector<foo>({ obj }))).first;
    }

  private:
    map_type          *map;
    map_type::iterator it;
    int                last_x;
};

int main()
{
    std::vector<foo> foos;
    std::map<int, std::vector<foo>> foos_by_x;

    foos.push_back({ 1, "one", 1.0 });
    foos.push_back({ 3, "third", 2.5 });
    foos.push_back({ 1, "one.. but third", 1.5 });
    foos.push_back({ 2, "second", 1.8 });
    foos.push_back({ 1, "one.. but second", 1.5 });

    std::sort(foos.begin(), foos.end(), [](const foo & lhs, const foo & rhs) {
            return lhs.x < rhs.x;
        });

    std::for_each(foos.begin(), foos.end(), optimized_inserter(foos_by_x));

    for (const auto & p : foos_by_x) {
        std::cout << "--- " << p.first << "---\n";
        for (auto & f : p.second) {
            std::cout << '\t' << f.x << " '" << f.y << "' / " << f.z << '\n';
        }
    }
}
于 2012-09-09T01:52:14.420 に答える
0

すべての LINQ を含むboolinq.hを使用するだけです。ドキュメントはありませんが、使い方はとても簡単です。

于 2021-11-15T01:38:38.567 に答える