Самый «функциональный» способ суммирования пар элементов из вектора с использованием C ++ 17 или более поздней версии? - PullRequest
5 голосов
/ 31 мая 2019

Я хотел бы получить несколько предложений о наиболее кратком и «функциональном» способе сбора пар последовательных элементов из вектора (1-й и 2-й, 3-й и 4-й и т. Д.) С использованием современного C ++. Предположим, вектор произвольной, но четной длины. Для примеров, которые я собираю, я суммирую элементы каждой пары, но это не главная проблема. Я должен добавить, что буду использовать только 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

Ответы [ 3 ]

7 голосов
/ 31 мая 2019

Использование 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)) { ... }
0 голосов
/ 01 июня 2019

Рискуя, будто я пытаюсь быть умным или раздражающим, я говорю, что это ответ:

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

Теперь, конечно, это не встроенные функции, поэтомуВы должны были бы определить их, но я не думаю, что это плохо.Код четко выражает то, что вы хотите в функциональном стиле.Кроме того, ответственность каждой из этих функций хорошо разделена, легко тестируема и может использоваться повторно.Для написания кода в функциональном стиле необязательно использовать много сложного специализированного синтаксиса.

0 голосов
/ 01 июня 2019

Без использования range-v3 я смог сделать это либо с помощью функции, либо с помощью лямбда-шаблона.Я покажу лямбда-версию здесь.

#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!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...