jjcasmar
jjcasmar

Reputation: 1685

Generate 2 vectors using ranges-v3

I have two vectors, of different types, lets say int and double. I also have a third vector with indices and I want to extract the values of the two first vectors corresponding to the indices with range-v3.

Right now I have this

std::vector<int> A {0,1,2,3,4,5,6,7,8};
std::vector<double> B{0,1,2,3,4,5,6,7,8};
std::vector<int> indices{0,2,3};

const std::vector<int> A_slice = indices | 
    ranges::views::transform([](const auto i) {return 2*i;}) | 
    ranges::views::transform([&A](const auto i) {return A[i]}) |
    ranges::to_vector;

const std::vector<double> B_slice = indices | 
    ranges::views::transform([](const auto i) {return 2*i;}) | 
    ranges::views::transform([&B](const auto i) {return B[i]}) | 
    ranges::to_vector;

This is not the most efficient way, as you need to iterate twice and do the 2*i transform twice. One solution would be to get a vector of pairs

const auto AB_slice = indices | 
    ranges::views::transform([](const auto i) {return 2*i;}) | 
    ranges::views::transform([&A, &B](const auto i) {return std::make_pair(A[i], B[i]);}) |
    ranges::to_vector;

but this is different from two separate vectors. Is there a way to obtain two separate vectors?

Upvotes: 1

Views: 216

Answers (1)

KamilCuk
KamilCuk

Reputation: 141900

So accumulate them yourself, if you want to:

#include <algorithm>
#include <vector>
#include <numeric>
#include <utility>
#include <iostream>
#include <range/v3/all.hpp>
int main() {
    std::vector<int> A {0,1,2,3,4,5,6,7,8};
    std::vector<double> B{0,1,2,3,4,5,6,7,8};
    std::vector<int> indices{0,2,3};

    const auto AB_slice = ranges::accumulate(
        indices | ranges::views::transform([](const auto i) {return 2*i;}),
        std::pair<std::vector<int>, std::vector<double>>(),
        [&](std::pair<std::vector<int>, std::vector<double>> v, int i) { 
            v.first.push_back(A[i]);
            v.second.push_back(B[i]);
            return std::move(v);
        }
    );

    for (auto i : AB_slice.first) {
        std::cout << i << "\n";
    }
    for (auto i : AB_slice.second) {
        std::cout << i << "\n";
    }
}

Upvotes: 1

Related Questions