如何优雅高效地将矢量元素分组到地图中?

时间:2017-08-04 14:04:45

标签: c++11 stl grouping

我正在分组'将矢量元素转换成地图,是否有更高效或更优雅的方式来做,而不是我目前的apporach? - 我认为它代码相当麻烦,并且在性能方面不是最佳的。

我来自C#,我通常会使用这样的方式来解决这种情况:

var groupedObservations = observations.GroupBy(o => o.x, o => o.y,o => o.z);

在我目前的C ++中,我首先对包含所有元素的向量进行排序,然后使用if语句我确定何时应该启动新组并推送所有后续的等号'元素进入该组。

我目前的代码如下;

struct Observation { int id; double x,y,z; }
vector<std::shared_ptr<Observation>> observations; 

..code that fills observations from csv is omitted ..

map<int,vector<shared_ptr<Observation>>> groupedObservations;


std::sort(observations.begin(), observations.end(), sorting_functor());

int groupId = 0;
double x =0 ,y =0 ,z = 0;
for(shared_ptr<Observation> &observation: observations)
{
    if(!(x == record->x && y== observation->y && z == observation->z))
    {
        groupId++; //coordinates different; new group.
        x = observation->x;
        y = observation->y;
        z = observation->z;

    }
    groupedObservations[groupId].push_back(observation);
}

为了完整性,排序函子如下:

struct sorting_functor
{
    bool operator()(const shared_ptr<Observation> &a, shared_ptr<Observation> &b) const
    {
        return (a->x < b->x) && (a->y < b->y) && (a->z < b->z);
    }
};

1 个答案:

答案 0 :(得分:1)

一个工作示例:

#include <unordered_set>
#include <iostream>
#include <boost/functional/hash.hpp>
#include <tuple>

struct Observation { int id; double x,y,z; };
namespace std
{
template<typename... T>
struct hash<tuple<T...>>
{
    size_t operator()(tuple<T...> const& arg) const noexcept {
        return boost::hash_value(arg);
    }
};

template<>
struct hash<Observation>
{
    size_t operator()(const Observation& o) const
    {
        tuple<double, double, double> t{o.x, o.y, o.z};
        return hash<tuple<double, double, double> >()(t);
    }
};

}

std::ostream& operator<<(std::ostream& os, Observation o) {
    return os<<o.id<<' '<<o.x<<' '<<o.y<<' '<<o.z;
}
bool operator==(const Observation& a, const Observation& b) {
    return a.x==b.x && a.y==b.y && a.z==b.z;
}

int main(int argc, char *argv[])
{
    std::vector<Observation> a = {
        {1, 1.0,1.0,1.1},
        {2, 1.0,1.0,1.1},
        {3, 3.0,3.0,3.3},
        {4, 1.0,1.0,1.1},
        {5, 3.0,3.0,3.3},
        {6, 5.0,5.0,5.5},
        {7, 5.0,5.0,5.5},
        {8, 5.0,5.0,5.5},
        {9, 2.0,2.0,2.2},
        {10,2.0,2.0,2.2},
        {11,5.0,5.0,5.5},
        {12,4.0,4.0,4.4},
    };
    std::unordered_multiset<Observation> words;
    words.insert(a.begin(), a.end());
    for(auto it = words.begin(); it != words.end(); )
    {
        auto cnt = words.count(*it);
        for(auto i=0;i<cnt;i++)
            std::cout << *it++ << '\n';
        std::cout<<'\n';
    }
    return 0;
}

给出了

10 2 2 2.2
9 2 2 2.2

11 5 5 5.5
8 5 5 5.5
7 5 5 5.5
6 5 5 5.5

5 3 3 3.3
3 3 3 3.3

12 4 4 4.4

4 1 1 1.1
2 1 1 1.1
1 1 1 1.1

您也可以像以前一样对矢量进行排序,然后使用https://github.com/Dobiasd/FunctionalPlus/blob/master/include/fplus/split.hpp,它为您提供非常干净的代码样式。

auto vector_of_vector = fplus::group(your_vector);