Как выполнить запрос 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
или простой массив, который будет быстрее; и если вы не можете, вероятно, бесполезно беспокоиться о распараллеливании.