Примеры разворачивания коллекции через std::accumulate
sekrasoft opened this issue · 4 comments
Стоит добавить в лекцию что-то про мощь std::accumulate
, например с наивным копированием:
#include <iostream>
#include <vector>
#include <numeric>
int main() {
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::vector<int> v1 = std::accumulate(v.begin(), v.end(), std::vector<int>(),
[](std::vector<int> xs, int x){ xs.push_back(x); return xs; });
std::cout << "copy:";
for (auto& x : v1) std::cout << " " << x;
std::cout << std::endl;
std::vector<int> v2 = std::accumulate(v.begin(), v.end(), std::vector<int>(),
[](std::vector<int> xs, int x){ xs.insert(xs.begin(), x); return xs; });
std::cout << "reversed:";
for (auto& x : v2) std::cout << " " << x;
std::cout << std::endl;
return 0;
}
Или на ссылках, хотя там функциональная чистота теряется.
А не лучше ли второй пример написать так:
std::vector<int> v2 = std::accumulate(v.rbegin(), v.rend(), std::vector<int>(),
[](std::vector<int> xs, int x){ xs.push_back(x); return xs; });
Ну и я совсем не уверен, что эти примеры показывают хороший стиль программирования. Мы обсуждаем выразительность и читабельность кода. А тут с помощью accumulate делаются не очевидные на первый взгляд вещи. std::copy здесь куда уместнее. Нет ли каких-нибудь реалистичных примеров, где accumulate действительно выручает неочевидным образом? И даже copy здесь не нужен. И первый и второй случаи решаются с помощью конструктора из двух итераторов...
А не лучше ли второй пример написать так:
std::vector<int> v2 = std::accumulate(v.rbegin(), v.rend(), std::vector<int>(), [](std::vector<int> xs, int x){ xs.push_back(x); return xs; });
Наверно лучше. Раз в коде не используется конструктор 2-кортежа или списка, полной аналогии ФП нет, не грешно улучшить код со стороны C++.
Ну и я совсем не уверен, что эти примеры показывают хороший стиль программирования. Мы обсуждаем выразительность и читабельность кода. А тут с помощью accumulate делаются не очевидные на первый взгляд вещи. std::copy здесь куда уместнее.
Это чисто ради расширения сознания и указания математической возможности. Чтобы не застревал шаблон в голове, что это просто отображение из коллекции и элемента в элемент, а отображение из коллекции и чего угодно во что угодно.
А дальше можно пояснить, что программирование отличается от математики, и код можно переписать так, чтобы он делал эквивалентное, но быстрее.
Нет ли каких-нибудь реалистичных примеров, где accumulate действительно выручает неочевидным образом? И даже copy здесь не нужен. И первый и второй случаи решаются с помощью конструктора из двух итераторов...
У меня наоборот есть антипример с подсчётом неправильной дисперсии за один проход.
Когда коллекция сворачивается по
f ((sx, sx2), x) = (sx+x, sx2+x*x)
(sx0, sx20) = (0, 0)
и при взятии (sx2-sx^2)/n
точность теряется.
Надо посмотреть код моего сервера. Там активно используются map, reduce, filter. Где-то там был код, который сшивал перекрывающиеся диапазоны.