Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to slice a `std::vector` based on elements in `std::set`

Tags:

c++

Is there a good way to slice a std::vector based on elements in a std::set? In other words, the elements in the std::set hold the indices that I want in the vector. Certainly, I can accomplish this with the code:

#include <set>
#include <vector>
#include <iostream>
#include <iterator>

template <typename T>
std::vector <T> slice(
    std::vector <T> const & x,
    std::set <unsigned int> const & I
) {
    auto y = std::vector <T> ();
    for(auto const & i : I)
        y.push_back(x[i]);
    return y;
}

int main() {
    auto x = std::vector <double> { 1.2, 2.3, 3.4, 4.5, 5.6};
    auto I = std::set <unsigned int> { 0, 3, 4};
    auto y = slice(x,I);
    std::copy(y.begin(),y.end(),std::ostream_iterator <double>(
        std::cout,"\n"));
}

which correctly returns

1.2
4.5
5.6

However, this feels a little clumsy. Is there a better way?

like image 925
wyer33 Avatar asked Feb 23 '16 23:02

wyer33


2 Answers

You can achieve this by simply using std::transform:

int main()
{
  std::vector<double> x { 1.2, 2.3, 3.4, 4.5, 5.6};
  std::set<unsigned int> I { 0, 3, 4};
  std::vector<double> y(I.size());

  std::transform(I.begin(), I.end(), y.begin(),
    [&x](unsigned int i) { return x[i]; });

  std::copy(y.begin(),y.end(),std::ostream_iterator <double>(std::cout,"\n"));  
}
like image 87
mcserep Avatar answered Sep 27 '22 22:09

mcserep


You could also use std::transform and std::back_inserter

template <typename T>
std::vector <T> slice(
    std::vector<T> const &x,
    std::set<unsigned int> const &I) 
{
    std::vector<double> result;
    std::transform(I.begin(), I.end(), std::back_inserter(result),
        [&x](unsigned int i) { return x[i]; });
    return result;
}
like image 38
nasser-sh Avatar answered Sep 27 '22 22:09

nasser-sh