Как выполнить запрос GroupBy Sum к списку?

Фон

Я работал с C#.Net + LINQ, где это было возможно, и пробовал свои силы в разработке C++ для проекта, в котором я участвую. Конечно, я полностью осознаю, что C# и C++ - это два разных мира.

Вопрос

у меня есть std::list<T> где T это структура следующим образом:

struct SomeStruct{
    int id;
    int rate;
    int value;
};

Мне нужно получить результат группы по rate и сумма value, Как я могу выполнить статистическую функцию GroupBy Sum в этом списке?

Пример:

SomeStruct s1;
SomeStruct s2;
SomeStruct s3;

s1.id=1;
s1.rate=5;
s1.value=100;

s2.id=2;
s2.rate=10;
s2.value=50;

s3.id=3;
s3.rate=10;
s3.value=200;

std::list<SomeStruct> myList;
myList.push_front(s1);
myList.push_front(s2);
myList.push_front(s3);

С этими входами я хотел бы получить следующий вывод:

rate|value
----|-----
   5|  100
  10|  250

Я нашел несколько многообещающих библиотек, таких как CINQ и cppitertools. Но я не мог полностью понять, поскольку у меня нет достаточных знаний. Было бы здорово, если бы кто-то направил меня в правильном направлении, я более чем готов изучать новые вещи.

1 ответ

Решение

Вычисление суммы Group-By относительно просто:

using sum_type = int; // but maybe you want a larger type
auto num_groups = max_rate + 1;
std::vector<sum_type> rate_sums(num_groups); // this is initialized to 0
for(const auto& s : myList) {
    rate_sums[s.rate] += s.value;
}

это когда rate значения в пределах 0 а также max_rate, а также max_rate не слишком велик по сравнению с myList.size(); в противном случае использование памяти может быть чрезмерным (и у вас будут некоторые издержки при инициализации вектора).

Если rate Значения разбросаны по большому диапазону относительно myList.size()рассмотрите возможность использования std::unoredered_map вместо std::vector).

Код выше также может быть распараллелен. Способ его распараллеливания зависит от вашего аппаратного обеспечения, и для этого есть множество библиотек. В C++20 могут быть языковые средства для распараллеливания.

Помните, однако, что связанные списки работают довольно медленно, потому что вам нужно разыменовать произвольный адрес для перехода от одного элемента к другому. Если вы можете получить свой вклад в std::vector или простой массив, который будет быстрее; и если вы не можете, вероятно, бесполезно беспокоиться о распараллеливании.

Другие вопросы по тегам