ranges::views::group_by-подобная функция, применяющая предикат к последовательным элементам?
В следующем небольшом примере я пытался сгруппировать элементы по разнице между последовательными элементами, равной 1. Однако, как показывает вывод,
group_by
Предикат оценивается между текущим элементом и первым элементом обрабатываемой группы.
#include <iostream>
#include <range/v3/view/group_by.hpp>
int main() {
using ranges::views::group_by;
std::vector<int> v{1,2,3,6,7,8,9,12,14,15};
for (auto i : v | group_by([](auto x2,auto x1){ return x2 - x1 == 1; })) {
std::cout << i << '\n';
}
}
Предлагает ли Range-v3 способ оценки предиката между последовательными элементами группы?
Однажды я задал тот же вопрос для Haskell, и оказалось, что одноименная функция есть на Hackage.
2 ответа
group_by
устарел в пользуchunk_by
, который делает именно то, что вы хотите:
Учитывая исходный диапазон и двоичный предикат, вернуть диапазон диапазонов, где каждый диапазон содержит непрерывные элементы из исходного диапазона, так что выполняется следующее условие: для каждого элемента в диапазоне, кроме первого, когда этот элемент и предыдущий элемент передается бинарному предикату, результат истинен. По сути,
views::chunk_by
группирует смежные элементы вместе с бинарным предикатом.
using ranges::views::chunk_by;
std::vector<int> v{1,2,3,6,7,8,9,12,14,15};
for (auto i : v | chunk_by([](auto l, auto r){ return r - l == 1; })) {
std::cout << i << '\n';
}
Отпечатки
[1,2,3]
[6,7,8,9]
[12]
[14,15]
Это уродливый результат моей попытки собрать то, что уже есть в Range-v3, чтобы получить то, что я хотел.
#include <iostream>
#include <range/v3/view/group_by.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/view/concat.hpp>
#include <range/v3/view/zip_with.hpp>
constexpr auto elem_and_distance_from_previous
= [](int x, int y){ return std::make_pair(x,x - y); };
constexpr auto second_is_1 = [](auto,auto x){ return x.second == 1; };
constexpr auto get_first = [](auto x){ return x.first; };
using namespace ranges::views;
int main() {
std::vector<int> v{1,2,3,6,7,8,9,12,14,15};
auto w = zip_with(elem_and_distance_from_previous,v,concat(iota(0,1),v))
| group_by(second_is_1)
| transform([](auto x){ return x | transform(get_first); });
std::cout << w << '\n';
}
// outputs [[1,2,3],[6,7,8,9],[12],[14,15]]
Вероятно, как предложил @einpoklum в комментарии, копия-вставка-редактирование оригинала
group_by
было бы намного лучше. Однако я задал этот вопрос, потому что хотел знать, есть ли уже в Range-v3 способ сделать то, что я имел в виду.