Related
I have a vector that holds items that are either active or inactive. I want the size of this vector to stay small for performance issues, so I want items that have been marked inactive to be erased from the vector. I tried doing this while iterating but I am getting the error "vector iterators incompatible".
vector<Orb>::iterator i = orbsList.begin();
while(i != orbsList.end()) {
bool isActive = (*i).active;
if(!isActive) {
orbsList.erase(i++);
}
else {
// do something with *i
++i;
}
}
The most readable way I've done this in the past is to use std::vector::erase combined with std::remove_if. In the example below, I use this combination to remove any number less than 10 from a vector.
(For non-c++0x, you can just replace the lambda below with your own predicate:)
// a list of ints
int myInts[] = {1, 7, 8, 4, 5, 10, 15, 22, 50. 29};
std::vector v(myInts, myInts + sizeof(myInts) / sizeof(int));
// get rid of anything < 10
v.erase(std::remove_if(v.begin(), v.end(),
[](int i) { return i < 10; }), v.end());
I agree with wilx's answer. Here is an implementation:
// curFiles is: vector < string > curFiles;
vector< string >::iterator it = curFiles.begin();
while(it != curFiles.end()) {
if(aConditionIsMet) {
it = curFiles.erase(it);
}
else ++it;
}
You can do that but you will have to reshuffle your while() a bit, I think. The erase() function returns an iterator to the element next after the erased one: iterator erase(iterator position);. Quoting from the standard from 23.1.1/7:
The iterator returned from a.erase(q)
points to the element immediately
following q prior to the element being
erased. If no such element exists,
a.end() is returned.
Though maybe you should be using the Erase-remove idiom instead.
erase returns a pointer to the next iterator value (same as Vassilis):
vector <cMyClass>::iterator mit
for(mit = myVec.begin(); mit != myVec.end(); )
{ if(condition)
mit = myVec.erase(mit);
else
mit++;
}
If someone need working on indexes
vector<int> vector;
for(int i=0;i<10;++i)vector.push_back(i);
int size = vector.size();
for (int i = 0; i < size; ++i)
{
assert(i > -1 && i < (int)vector.size());
if(vector[i] % 3 == 0)
{
printf("Removing %d, %d\n",vector[i],i);
vector.erase(vector.begin() + i);
}
if (size != (int)vector.size())
{
--i;
size = vector.size();
printf("Go back %d\n",size);
}
}
As they said, vector's iterators get invalidated on vector::erase() no matter which form of iterator increment you use. Use an integer index instead.
You might want to consider using a std::list instead of a std::vector for your data structure. It is safer (less bug prone) to use when combining erasure with iteration.
Removing items from the middle of a vector will invalidate all iterators to that vector, so you cannot do this (update: without resorting to Wilx's suggestion).
Also, if you're worried about performance, erasing items from the middle of a vector is a bad idea anyway. Perhaps you want to use an std::list?
I have a vector that holds items that are either active or inactive. I want the size of this vector to stay small for performance issues, so I want items that have been marked inactive to be erased from the vector. I tried doing this while iterating but I am getting the error "vector iterators incompatible".
vector<Orb>::iterator i = orbsList.begin();
while(i != orbsList.end()) {
bool isActive = (*i).active;
if(!isActive) {
orbsList.erase(i++);
}
else {
// do something with *i
++i;
}
}
The most readable way I've done this in the past is to use std::vector::erase combined with std::remove_if. In the example below, I use this combination to remove any number less than 10 from a vector.
(For non-c++0x, you can just replace the lambda below with your own predicate:)
// a list of ints
int myInts[] = {1, 7, 8, 4, 5, 10, 15, 22, 50. 29};
std::vector v(myInts, myInts + sizeof(myInts) / sizeof(int));
// get rid of anything < 10
v.erase(std::remove_if(v.begin(), v.end(),
[](int i) { return i < 10; }), v.end());
I agree with wilx's answer. Here is an implementation:
// curFiles is: vector < string > curFiles;
vector< string >::iterator it = curFiles.begin();
while(it != curFiles.end()) {
if(aConditionIsMet) {
it = curFiles.erase(it);
}
else ++it;
}
You can do that but you will have to reshuffle your while() a bit, I think. The erase() function returns an iterator to the element next after the erased one: iterator erase(iterator position);. Quoting from the standard from 23.1.1/7:
The iterator returned from a.erase(q)
points to the element immediately
following q prior to the element being
erased. If no such element exists,
a.end() is returned.
Though maybe you should be using the Erase-remove idiom instead.
erase returns a pointer to the next iterator value (same as Vassilis):
vector <cMyClass>::iterator mit
for(mit = myVec.begin(); mit != myVec.end(); )
{ if(condition)
mit = myVec.erase(mit);
else
mit++;
}
If someone need working on indexes
vector<int> vector;
for(int i=0;i<10;++i)vector.push_back(i);
int size = vector.size();
for (int i = 0; i < size; ++i)
{
assert(i > -1 && i < (int)vector.size());
if(vector[i] % 3 == 0)
{
printf("Removing %d, %d\n",vector[i],i);
vector.erase(vector.begin() + i);
}
if (size != (int)vector.size())
{
--i;
size = vector.size();
printf("Go back %d\n",size);
}
}
As they said, vector's iterators get invalidated on vector::erase() no matter which form of iterator increment you use. Use an integer index instead.
You might want to consider using a std::list instead of a std::vector for your data structure. It is safer (less bug prone) to use when combining erasure with iteration.
Removing items from the middle of a vector will invalidate all iterators to that vector, so you cannot do this (update: without resorting to Wilx's suggestion).
Also, if you're worried about performance, erasing items from the middle of a vector is a bad idea anyway. Perhaps you want to use an std::list?
I was asked the following question in a 30-minute interview:
Given an array of integers, remove the duplicates without using any STL containers. For e.g.:
For the input array [1,2,3,4,5,3,3,5,4] the output should be:
[1,2,3,4,5];
Note that the first 3, 4 and 5 have been included, but the subsequent ones have been removed since we have already included them once in the output array. How do we do without using an extra STL container?
In the interview, I assumed that we only have positive integers and suggested using a bit array to mark off every element present in the input (assume every element in the input array as an index of the bit array and update it to 1). Finally, we could iterate over this bit vector, populating (or displaying) the unique elements. However, he was not satisfied with this approach. Any other methods that I could have used?
Thanks.
Just use std::sort() and std::unique():
int arr[] = { 1,2,3,4,5,3,3,5,4 };
std::sort( std::begin(arr), std::end(arr) );
auto end = std::unique( std::begin(arr), std::end(arr) );
Live example
We can first sort the array then check if the next element is equal to the previous one and finally give the answer with the help of another array of size 2 larger than the previous one like this.
Initialize the second array with a value that first array will not take (any number larger/smaller than the limit given) ,suppose 0 for simplicity then
int arr1[] = { 1,2,3,4,5,3,3,5,4 };
int arr2[] = { 0,0,0,0,0,0,0,0,0,0,0 };
std::sort( std::begin(arr1), std::end(arr1) );
int position=1;
arr2[0] = arr1[0];
for(int* i=begin(arr1)+1;i!=end(arr1);i++){
if((*i)!=(*(i-1))){
arr2[position] = (*i);
position++;
}
}
int size = 0;
for(int* i=begin(arr2);i!=end(arr2);i++){
if((*i)!=(*(i+1))){
size++;
}
else{
break;
}
}
int ans[size];
for(int i=0;i<size;i++){
ans[i]=arr2[i];
}
Easy algorithm in O(n^2):
void remove_duplicates(Vec& v) {
// range end
auto it_end = end(v);
for (auto it = begin(v); it != it_end; ++it) {
// remove elements matching *it
it_end = remove(it+1, it_end, *it);
}
// erase now-unused elements
v.erase(it_end, end(v));
}
See also erase-remove idiom
Edit: This is assuming you get a std::vector in, but it would work with C-style arrays too, you would just have to implement the erasure yourself.
I have two data structures with data in them.
One is a vector std::vector<int> presentStudents And other is a
char array char cAllowedStudents[256];
Now I have to compare these two such that checking every element in vector against the array such that all elements in the vector should be present in the array or else I will return false if there is an element in the vector that's not part of the array.
I want to know the most efficient and simple solution for doing this. I can convert my int vector into a char array and then compare one by one but that would be lengthy operation. Is there some better way of achieving this?
I would suggest you use a hash map (std::unordered_map). Store all the elements of the char array in the hash map.
Then simply sequentially check each element in your vector whether it is present in the map or not in O(1).
Total time complexity O(N), extra space complexity O(N).
Note that you will have to enable C++11 in your compiler.
Please refer to function set_difference() in c++ algorithm header file. You can use this function directly, and check if result diff set is empty or not. If not empty return false.
A better solution would be adapting the implementation of set_difference(), like in here: http://en.cppreference.com/w/cpp/algorithm/set_difference, to return false immediately after you get first different element.
Example adaption:
while (first1 != last1)
{
if (first2 == last2)
return false;
if (*first1 < *first2)
{
return false;
}
else
{
if (*first2 == *first1)
{
++first1;
}
++first2;
}
}
return true;
Sort cAllowedstudents using std::sort.
Iterate over the presentStudents and look for each student in the sorted cAllowedStudents using std::binary_search.
If you don't find an item of the vector, return false.
If all the elements of the vector are found, return true.
Here's a function:
bool check()
{
// Assuming hou have access to cAllowedStudents
// and presentStudents from the function.
char* cend = cAllowedStudents+256;
std::sort(cAllowedStudents, cend);
std::vector<int>::iterator iter = presentStudents.begin();
std::vector<int>::iterator end = presentStudents.end();
for ( ; iter != end; ++iter )
{
if ( !(std::binary_search(cAllowedStudents, cend, *iter)) )
{
return false;
}
}
return true;
}
Another way, using std::difference.
bool check()
{
// Assuming hou have access to cAllowedStudents
// and presentStudents from the function.
char* cend = cAllowedStudents+256;
std::sort(cAllowedStudents, cend);
std::vector<int> diff;
std::set_difference(presentStudents.begin(), presentStudents.end(),
cAllowedStudents, cend,
std::back_inserter(diff));
return (diff.size() == 0);
}
Sort both lists with std::sort and use std::find iteratively on the array.
EDIT: The trick is to use the previously found position as a start for the next search.
std::sort(begin(pS),end(pS))
std::sort(begin(aS),end(aS))
auto its=begin(aS);
auto ite=end(aS);
for (auto s:pS) {
its=std::find(its,ite,s);
if (its == ite) {
std::cout << "Student not allowed" << std::cout;
break;
}
}
Edit: As legends mentiones, it usually might be more efficient to use binary search (as in R Sahu's answer). However, for small arrays and if the vector contains a significant fraction of students from the array (I'd say at least one tenths), the additional overhead of binary search might (or might not) outweight its asymptotic complexity benefits.
Using C++11. In your case, size is 256. Note that I personally have not tested this, or even put it into a compiler. It should, however, give you a good idea of what to do yourself. I HIGHLY recommend testing the edge cases with this!
#include <algorithm>
bool check(const std::vector<int>& studs,
char* allowed,
unsigned int size){
for(auto x : studs){
if(std::find(allowed, allowed+size-1, x) == allowed+size-1 && x!= *(allowed+size))
return false;
}
return true;
}
I create a vector inside with several elements in c++ and I want to remove the elements of vector with the same values. Basically, I want to remove the whole index of the vector that is found a duplicate element. My vector is called person. I am trying to do something like:
for(int i=0; i < person.size(); i++){
if(i>0 && person.at(i) == person.at(0:i-1)) { // matlab operator
continue;
}
writeToFile( perason.at(i) );
}
How is it possible to create the operator 0:i-1 to check all possible combinations of indexes?
Edit: I am trying GarMan solution but I got issues in for each:
set<string> myset;
vector<string> outputvector;
for (string element:person)
{
if (myset.find(element) != myset.end())
{
myset.insert(element);
outputvector.emplace_back(element);
}
}
Here is an "in-place" version (no second vector required) that should work with older compilers:
std::set<std::string> seen_so_far;
for (std::vector<std::string>::iterator it = person.begin(); it != person.end();)
{
bool was_inserted = seen_so_far.insert(*it).second;
if (was_inserted)
{
++it;
}
else
{
swap(*it, person.back());
person.pop_back();
}
}
Let me know if this works for you. Note that the order of elements is not guaranteed to stay the same.
Something like this will work
unordered_set<same_type_as_vector> myset;
vector<same_type_as_vector> outputvector;
for (auto&& element: myvector)
{
if (myset.find(element) != myset.end())
{
myset.insert(element);
outputvector.emplace_back(element);
}
}
myvector.swap(outputvector);
Code written into reply box, so might need tweaking.
If you can sort your vector, you can simply call std::unique.
#include <algorithm>
std::sort(person.begin(), person.end());
person.erase(std::unique(person.begin(), person.end()), person.end());
If you cannot sort, you can use a hash-table instead by scanning the vector and update the hash-table accordingly. On the same time, you can easily check if one element is already existent or not in O(1) (and O(n) in total). You don't need to check all other elements for each one, which will be time-costly O(n^2).