I'm looking for the most efficient way to remove multiple items from a vector?
Basically I will be searching for a flag within the vector and removing and objects that have that flag.
However, I have heard that erasing an object from a vector will mess up your iterators, so what is the most efficient way to loop though a vector (containing potentially thousands of objects) and remove those with a specific flag?
I am hoping to not have to loop through the vector multiple times.
If there are multiple elements match the flag you should use std::remove_if():
vec.erase(std::remove_if(vec.begin(), v.end(), [](T const& e){ return e.flag(); }),
v.end());
Using this approach moves each vector element at most once. Removing individual elements may move each element O(n) times.
The std::remove_if algorithm can sometimes be coupled elegantly with other utilities. For example, if your class looks like this:
struct Foo
{
bool flag; // either this...
bool get_flag() const; // ... or this
// ...
};
Then you can use std::mem_fn to generate an accessor functor that returns the value of the member or invokes the member function, respectively:
std::mem_fn(&Foo::flag)
std::mem_fn(&Foo::get_flag)
Finally, you can use argument-dependent lookup to rely on namespace std to be found as soon as one of the argument types is from that namespace. For example:
#include <algorithm> // for remove_if
#include <functional> // for mem_fn
#include <iterator> // for begin, end
#include <vector> // for vector
std::vector<Foo> v = /* something */ ;
v.erase(remove_if(begin(v), end(v), std::mem_fn(&Foo::flag)), end(v));
Related
I have an unordered_set that stores the following struct
struct match_t{
size_t score;
size_t ci;
};
typedef std::unordered_set<match_t> uniq_t;
Now I want to store the elements of uniq_t myset; to a vector, but in doing so, I want to copy just the score and not the entire struct. I have seen solutions for assigning the elements using assign or back_inserter. I was wondering how to select just the required fields from the struct. I don't see any parameter in assign or back_inserter for this purpose.
Should I try overriding push_back method for the vector or are there other methods for doing this?
EDIT 1
Do I get any performance improvements by using any of these methods instead of looping over the set and assigning the required values?
There is nothing wrong a simple for loop:
std::unordered_set<match_t> myset;
std::vector<std::size_t> myvec;
myvec.reserve(myset.size()); // allocate memory only once
for (const auto& entry : myset)
myvec.push_back(entry.score);
Alternatively, you could use std::transform with a custom lambda:
#include <algorithm>
std::tranform(myset.cbegin(), myset.cend(), std::back_inserter(myvec),
[](const auto& entry){ return entry.score; });
Another way is to use a range library, e.g. with range-v3
#include <range/v3/view/transform.hpp>
std::vector<std::size_t> myvec = myset | ranges::view::transform(&match_t::score);
Performance-wise, you can't do anything about the linear pass over all match_t objects. The important tweak instead is to minimize the number of allocations. As the size of the resulting std::vector is known a priori, a call to std::vector::reserve as shown above makes sure that no unnecessary allocation occur.
I need a data structure like std::vector or std::list whose elements will be unique. In most of time I will call push_back on it, sometimes maybe erase. When I insert an element which is already there, I need to be notified either by some boolean or exception.
And the most important property it should have: the order of insertions. Each time I iterate over it, it should return elements in the order they were inserted.
We can think other way: a queue which guarantees the uniqueness of elements. But I don't want to pop elements, instead I want to iterate over them just like we do for vector or list.
What is the best data structure for my needs?
You can use a std::set
It will return a pair pair<iterator,bool> when the insert method is called. The bool in the pair is false when the element already exists in the set (the element won't be added in that case).
Use a struct with a regular std::vector and a std::set.
When you push, check the set for existence of the element. When you need to iterate, iterate over the vector. If you need to erase from the vector, also erase from the set.
Basically, use the set as an aside, only for fast "presence of an element" check.
// either make your class a template or use a fixed type of element
class unique_vector
{
public:
// implement the various operator you need like operator[]
// alternatively, consider inheriting from std::vector
private:
std::set<T> m_set; // fast lookup for existence of elements
std::vector<T> m_vector; // vector of elements
};
I would prefer using std::unordered_set to stores existing elements in a std::vector and it has faster lookup time of O(1), while the lookup time of std::set is O(logn).
You can use Boost.MultiIndex for this:
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
using namespace boost::multi_index;
template<typename T>
using unique_list=multi_index_container<
T,
indexed_by<
sequenced<>,
hashed_unique<identity<T>>
>
>;
#include <iostream>
int main()
{
unique_list<int> l;
auto print=[&](){
const char* comma="";
for(const auto& x:l){
std::cout<<comma<<x;
comma=",";
}
std::cout<<"\n";
};
l.push_back(0);
l.push_back(1);
l.push_back(2);
l.push_back(0);
l.push_back(2);
l.push_back(4);
print();
}
Output
0,1,2,4
The following code checks if all elements in the declared array are odd numbers.
#include "stdafx.h"
#include <iostream> // std::cout
#include <algorithm> // std::all_of
#include <array> // std::array
int main () {
std::array<int,8> foo = {3,5,7,11,13,17,19,23};
if ( std::all_of(foo.begin(), foo.end(), [](int i){return i%2;}) )
std::cout << "All the elements are odd numbers.\n";
return 0;
}
(Sample taken from http://www.cplusplus.com/reference/algorithm/all_of)
I would like to check if all elements in the declared array starting from foo[2] are odd numbers.
Replacing foo.begin() with foo[2] does not work. I've tried many other things to make this work, all very basic (very basic C++ user here), without success. I do not want to resize the array for achieving this.
Ultimately what I'm looking for is having a loop where a condition is checked for on every element of part of an array, just as the for loop checks for a condition on any element of part of an array. This is relatively easy to achieve in R, and I'm hoping it may be equally easy to achieve in C++.
You can't use an iterator and an element here, they don't represent a range. In a more general sense, even attempting to use a pointer to an element and an iterator would not be well defined for all implementations of any given container either.
You should use std::next(it.begin(), 2) to increment to the begin() iterator to the foo[2] element and then you can iterate over the range with the two iterators.
std::all_of(std::next(foo.begin(), 2), foo.end(),
[](int i){/*...*/})
std::next() is more general and caters for iterators other than just random access iterators (e.g. for the alternate it.begin() + 2); but will still be performant for the type of iterator passed to it.
I am stuck on trying to figure out how to insert a vector for a value in a map. For example:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{
map <int, vector<int> > mymap;
mymap.insert(pair<int, vector<int> > (10, #put something here#));
return 0;
}
I don't know what syntax to use insert a vector for value. I tried {1,2}, but that failed. What syntax should I use?
Everything works if I declare a vector in advance and give it a name, but I don't want to do that, as I want to have a map with a lot of vectors.
Thank You in Advance
If you want an empty vector you could do:
mymap.insert(pair<int,vector<int> >(10, vector<int>()));
You could then add whatever elements you want with something like:
mymap[10].push_back(1);
mymap[10].push_back(2);
Edit: Removed incorrect assertion that the vectors would be copied if/when the map grows. As the commenters pointed out, this is not true for std::map, which is node-based.
Basically your question is not about inserting std::vector into a std::map. Your question is how can you easily create an anonymous std::vector with arbitrary initial element values.
In ISO C++03, you can't. C++11 allows using initialization lists for this, however.
If you are stuck with a C++03 compiler, you possibly could create a helper function to return a vector with specified elements:
std::vector<int> make_vector(int a, int b)
{
std::vector<int> v;
v.push_back(a);
v.push_back(b);
return v;
}
If the vectors you're inserting are of different sizes, you could use a variadic function, although doing so would require that you either pass along the number of elements or have a reserved sentinel value.
If you are using C++11 you can use vector's initialization list constructor (the last constructor in that list) which would look like this:
mymap.insert(pair<int, vector<int> > (10, {1, 2, 3}));
If you can only use C++03, vector has a constructor that takes a size and a default value for each element that might be enough for you. Otherwise you will have to construct the vector and then insert it. If you want to avoid an unnessicary copy of the vector when inserting you could swap it in like so:
vector<int> myvec;
myvec.push_back(1);
myvec.push_back(2);
mymap[10].swap(myvec);
This way the vector won't need to be copied. You'll get an extra vector default construction but that's not very expensive.
#put something here# = vector<int>{1,2}
I'm surprised though that {1,2} didn't work. Are you not using a C++11 compiler? If not then you can only create the vector with default constructor there (no values), or fill it with values first and stick it in.
This should work in C++2003 compilers.
#include <iostream>
#include <vector>
#include <map>
#include <cassert>
using namespace std;
std::vector<int> make_vector(int a, int b) {
std::vector<int> result;
result.push_back(a);
result.push_back(b);
return result;
}
int main()
{
map <int, vector<int> > mymap;
mymap.insert(make_pair(10, make_vector(1,2)));
// Or, alternatively:
// mymap[10] = make_vector(1,2);
assert(mymap[10][0] == 1);
assert(mymap[10][1] == 2);
return 0;
}
C++03 does not have initializer lists, which can be a pain to initialize collections.
If you cannot upgrade to a more modern version of the compiler, you can always use the Boost.Assignment library. It has a list_of function precisely for this.
#put something here# -> boost::assign::list_of(1)(2)
The standard way to remove certain elements from a vector in C++ is the remove/erase idiom. However, the predicate passed to remove_if only takes the vector element under consideration as an argument. Is there a good STL way to do this if the predicate is conditional on other elements of the array?
To give a concrete example, consider removing all duplicates of a number immediately following it. Here the condition for removing the n-th element is conditional on the (n-1)-th element.
Before: 11234555111333
After: 1234513
There's a standard algorithm for this. std::unique will remove the elements that are duplicates of those preceding them (actually, just like remove_if it reorganizes the container so that the elements to be removed are gathered at the end of it).
Example on a std::string for simplicity:
#include <string>
#include <iostream>
#include <algorithm>
int main()
{
std::string str = "11234555111333";
str.erase(std::unique(str.begin(), str.end()), str.end());
std::cout << str; // 1234513
}
Others mentioned std::unique already, for your specific example. Boost.Range has the adjacent_filtered adaptor, which passes both the current and the next element in the range to your predicate and is, thanks to the predicate, applicable to a larger range of problems. Boost.Range however also has the uniqued adaptor.
Another possibility would be to simply keep a reference to the range, which is easy to do with a lambda in C++11:
std::vector<T> v;
v.erase(std::remove_if(v.begin(), v.end(),
[&](T const& x){
// use v, with std::find for example
}), v.end());
In my opinion, there will be easier to use simple traversal algorithm(via for) rather then use std::bind. Of course, with std::bind you can use other functions and predicates(which depends on previous elements). But in your example, you can do it via simple std::unique.