使用 C++17 或更高版本对向量中的元素对求和的最'functional'方法?

Most 'functional' way to sum pairs of elements from a vector using C++17 or later?

本文关键字:求和 元素 和的 方法 functional 高版本 C++17 向量 版本 使用      更新时间:2023-10-16

我想得到一些建议,以最简洁和"功能"的方式使用现代C++从向量(第 1 和第 2、第 3 和第 4 等(收集连续元素对。 假设向量是任意但长度均匀的。 对于我放在一起的例子,我把每对的元素相加,但这不是主要问题。 我应该补充一点,我将只使用 STL,没有 Boost。

在 Python 中,我可以通过迭代器将它们压缩成 2 元组

s = range(1,11)
print([(x + y) for x,y in zip(*[iter(s)] * 2)])

在 Perl 5 中,我可以剥离成对

use List::Util qw/pairs sum/;
use feature 'say';
@s = 1 .. 10;
say sum @$_ foreach (pairs @s);

在Perl 6中,我可以一次将它们两个推入一个块中

my @s = 1 .. 10;
for @s -> $x, $y { say $x + $y; }

在 R 中,我可以将向量包装成一个 2 列数组并将行求和

s <- 1:10
print(apply(matrix(s, ncol=2, byrow=TRUE), 1, sum))

我C++不流利,我的解决方案使用 for(;;) . 这感觉太像C了。

#include <iostream>
#include <vector>
#include <numeric>  // std::iota
int main() {
    std::vector<int> s(10);
    std::iota(s.begin(), s.end(), 1);
    for (auto p = s.cbegin(); p != s.cend(); p += 2)
        std::cout << (*p + *(p + 1)) << std::endl;
}

输出当然应该是某种变体

3
7
11
15
19

使用 range-v3:

for (auto v : view::iota(1, 11) | view::chunk(2)) {
    std::cout << v[0] + v[1] << 'n';
}   

请注意,chunk(2) 不会为您提供编译时固定大小视图,因此您无法执行以下操作:

for (auto [x,y] : view::iota(1, 11) | view::chunk(2)) { ... }

不使用 range-v3,我可以使用函数或 lambda 模板来做到这一点。我将在这里展示 lambda 版本。

#include <iostream>
#include <string>
#include <vector>
template<typename T>
auto lambda = [](const std::vector<T>& values, std::vector<T>& results) {
    std::vector<T> temp1, temp2;
    for ( std::size_t i = 0; i < values.size(); i++ ) {
        if ( i & 1 ) temp2.push_back(values[i]); // odd index
        else temp1.push_back(values[i]); // even index
    }
    for ( std::size_t i = 0; i < values.size() / 2; i++ )
        results.push_back(temp[i] + temp[2]);
};
int main() {
    std::vector<int> values{ 1,2,3,4,5,6 };
    for (auto i : values)
        std::cout << i << " ";
    std::cout << 'n';
    std::vector<int> results;
    lambda<int>(values, results);
    for (auto i : results)
        std::cout << i << " ";
    std::cout << 'n';
    std::vector<float> values2{ 1.1f, 2.2f, 3.3f, 4.4f };
    for (auto f : values2)
        std::cout << f << " ";
    std::cout << 'n';
    std::vector<float> results2;
    lambda<float>(values2, results2);
    for (auto f : results2)
        std::cout << f << " ";
    std::cout << 'n';
    std::vector<char> values3{ 'a', 'd' };
    for (auto c : values3)
        std::cout << c << " ";
    std::cout << 'n';
    std::vector<char> results3;
    lambda<char>(values3, results3);
    for (auto c : results3)
        std::cout << c << " ";
    std::cout << 'n';
    std::vector<std::string> values4{ "Hello", " ", "World", "!" };
    for (auto s : values4)
        std::cout << s;
    std::cout << 'n';
    std::vector<std::string> results4;
    lambda<std::string>(values4, results4);
    for (auto s : results4)
        std::cout << s;
    std::cout << 'n';
   return EXIT_SUCCESS;
}

输出

1 2 3 4 5 6
3 7 11
1.1 2.2 3.3 4.4
3.3 7.7
a d
┼
Hello World!
Hello World!

冒着听起来像我试图变得聪明或烦人的风险,我说这就是答案:

print(sums(successive_pairs(range(1,11))));

当然,这些不是内置函数,所以你必须定义它们,但我不认为这是一件坏事。 代码以函数式风格清楚地表达了您想要的内容。 此外,每个函数的职责都是很好的分离的,易于测试和可重用。 没有必要使用很多棘手的专用语法来编写函数式风格的代码。