std :: transform для более чем двух векторов - PullRequest
4 голосов
/ 22 апреля 2020

Предполагается, что я хотел бы добавить два вектора a и b в вектор c

std::vector<double> a, b, c;
//Fill/Initialize vectors

Я могу использовать std::transform() или простой for -l oop:

//std::transform
std::transform(a.begin(),
               a.end(),
               b.begin(),
               c.begin(),
               [](const auto &a_val, const auto &b_val){
                  return a_val + b_val;
               });
//Loop
for(size_t i = 0; i < a.size(); ++i){
    c[i] = a[i] + b[i];
}

Обычно использование std::transform() рекомендуется сравнивать с for -l oop. К сожалению, насколько я знаю, я не могу сделать аналогичный подход, используя std::transform() для случая сложения больше векторов, чем двух, т.е. если я хотел бы сложить векторы a, b и c в д. Затем я возвращаюсь к-l oop, или мне нужно использовать два раунда std::transform(). Или есть способ использовать одну std::transform() -операцию (или что-то подобное) для работы более чем с двумя входными векторами одновременно?

Ответы [ 2 ]

4 голосов
/ 22 апреля 2020

Это правда, в стандартной библиотеке это невозможно std::transform более чем на 2 вектора. Но используя range-v3, вы можете сделать это с произвольным числом векторов, используя zip.

#include <include/range/v3/view/zip.hpp>

int main()
{
    std::vector<int> a{1,2,3};
    std::vector<int> b{2,3,4};
    std::vector<int> c{2,3,4};
    std::vector<int> d{2,3,4};

    std::vector<int> res;
    auto r = ranges::views::zip(a, b, c, d);
    std::transform(
        r.begin(),
        r.end(),
        std::back_inserter(res),
        [](const auto& tup) { return std::get<0>(tup); }
    );
}
1 голос
/ 22 апреля 2020

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

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

int main() {
    std::vector<int> a{1,2,3,4};
    std::vector<int> b{1,2,3,4};
    std::vector<int> c(a.size());

    std::vector<int> v(a.size());
    std::iota(v.begin(), v.end(),0);

    std::transform(v.begin(),
               v.end(),
               c.begin(),
               [&](const auto &i){
                  return a[i] + b[i];
               });

    for (const auto& e : c) std::cout << e << ' ';
    return 0;
}

Вы можете превратить лямбду во что-то более общее c, например, функтор, который работает с переменным c число векторы и добавляет их элементы.

Однако я бы предпочел l oop. Основным преимуществом алгоритмов является ясность, но если вам нужно прибегнуть к обходному пути, ясность теряется. Может быть, кто-то может доказать, что я неправ, и найти алгоритм, который может делать то, что вы хотите, из коробки;).

PS: на секунду подумал, что вышеупомянутое действительно глупо и злоупотребление алгоритмом. С помощью std::iota любой l oop может быть тривиально преобразован в использование алгоритма, но истинное значение std::transform «преобразовать один диапазон в другой» полностью теряется, что противоречит цели использования алгоритма в первом место.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...