C++ algorithm like python's 'groupby'

后端 未结 6 613
再見小時候
再見小時候 2020-12-15 22:20

Are there any C++ transformations which are similar to itertools.groupby()?

Of course I could easily write my own, but I\'d prefer to leverage the idiomatic behavior

6条回答
  •  情书的邮戳
    2020-12-15 23:07

    What is the point of bloating standard C++ library with an algorithm that is one line of code?

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

    Also, take a look at std::multimap, it might be just what you need.

    UPDATE:

    The one-liner I have provided is not well-optimized for the case when your vector is already sorted. A number of map lookups can be reduced if we remember the iterator of previously inserted object, so it the "key" of the next object and do a lookup only when the key is changing. For example:

    #include 
    #include 
    #include 
    #include 
    #include 
    
    struct foo {
        int         x;
        std::string y;
        float       z;
    };
    
    class optimized_inserter {
      public:
        typedef std::map > 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({ obj }))).first;
        }
    
      private:
        map_type          *map;
        map_type::iterator it;
        int                last_x;
    };
    
    int main()
    {
        std::vector foos;
        std::map> 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';
            }
        }
    }
    

提交回复
热议问题