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);
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);
           });
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With