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