Remove items from two vectors depending on the values inside one vector
Asked Answered
T

2

6

I have two integer vectors of equal length. Let's say I want to remove all items in the first vector which are NAN. Obviously, I use the remove_if algorithm. Let's say this removes elements that were at indexes 1,2,5. I then want to remove items from the second vector at these indexes.

What's the most canonical C++ way of doing this?

Topdress answered 30/10, 2014 at 16:20 Comment(2)
If they are related values, the most canonical way would be to put both pieces of data in the same object and have one vector containing those objects...Vivacious
like @Vivacious said, if you know they have the same length and the values are linked you should probably have a std::vector<std::pair<int,int>> in the first placeRatan
F
11

This can be done using Boost by creating a zip_iterator and then iterating over the tuple of iterators from both containers in parallel.

First pass a pair of zip_iterators to std::remove_if, and have the predicate inspect the elements of the first vector for NaN

auto result = std::remove_if(boost::make_zip_iterator(boost::make_tuple(v1.begin(), v2.begin())),
                             boost::make_zip_iterator(boost::make_tuple(v1.end(),   v2.end())),
                             [](boost::tuple<double, int> const& elem) {
                                 return std::isnan(boost::get<0>(elem));
                             });

Then use vector::erase to remove the unneeded elements.

v1.erase(boost::get<0>(result.get_iterator_tuple()), v1.end());
v2.erase(boost::get<1>(result.get_iterator_tuple()), v2.end());

Live demo


The boilerplate required to create the zipped iterator ranges can be further reduced by using boost::combine and Boost.Range's version of remove_if.

auto result = boost::remove_if(boost::combine(v1, v2),
                               [](boost::tuple<double, int> const& elem) {
                                    return std::isnan(boost::get<0>(elem));
                               });

Live demo

Feat answered 30/10, 2014 at 17:4 Comment(2)
This is awesome. Thanks! I chose to use boost::combine to produce a range which I could call begin() and end() on in remove_if, I presume there's no real difference?Guttery
@Guttery That's an excellent idea, cleans the code up quite a bit. I added that to the answer. Thanks!Feat
K
1

Use a vector<pair<int, int>> to tie the two vector together. Then, perform your remove based on the first element to and get rid of both at the same time.

Kernite answered 30/10, 2014 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.