Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C++20 What's the most succinct and clear way to compute on adjacent pairs in a range?

Tags:

c++

range

c++20

I bumped into a simple problem today and I realized with the modern ranges stuff and maybe other stuff in <algorithm> there must be an elegant way to express this in a line or so instead of this mess of six lines, but I don't know it.

Compute adjacent differences:

    std::vector<int> nums = {3841, 16342, 1941, 31299, 26416, 11243};

    auto it1 = std::begin(nums);
    auto it2 = it1;
    it2++;
    std::vector<int> adjacent_diffs;
    for (; it2 != std::end(nums); it1++, it2++) {
        adjacent_diffs.push_back(*it2 - *it1);
    }

This isn't really more succinct or elegant:

    auto diffop = [](int a, int b) { return b - a; };
    std::vector<int> adjacent_diffs;
    std::transform(std::begin(nums), std::end(nums) - 1, std::begin(nums) + 1,
         std::back_inserter(adjacent_diffs), diffop);

like image 871
rjt_jr Avatar asked Mar 03 '23 02:03

rjt_jr


1 Answers

Getting the adjacent differences is the same as zipping a range with its tail, using - as the operation:

tail: [16342, 1941,  31299, 26416, 11243]
  op:   -      -      -      -       -
nums: [3841,  16342, 1941,  31299, 26416, 11243]

Which, in range-v3 terms, would be:

auto adjacent_diffs = [](auto&& range){
    return views::zip_with(std::minus{},
        range | views::tail,
        range);
};

C++20 won't have zip_with though (or tail, though that's the same as drop(1)). What you could do, though, is either using the indices:

auto adjacent_diffs = [](auto&& range){
    return views::iota(1u, range.size())
         | views::transform([&](auto i){
               return range[i] - range[i-1];
           });
};

Or the iterators:

auto adjacent_diffs = [](auto&& range){
    return views::iota(std::next(range.begin()), range.end())
         | views::transform([&](auto it){
               return *it - *std::prev(it);
           });
};
like image 179
Barry Avatar answered Apr 30 '23 17:04

Barry