Consecutive removing of vector elements - c++

I need to remove element from vector a and b, if these elements are equal. As I understand, when I remove an element, other elements move. So, a[1] become a[0], a[2] -- a[1] and so on. But my code doesn`t work properly:
#include <iostream>
#include <vector>
using namespace std;
bool remove(vector<int>& a, vector<int>& b){
for (size_t i = 0; i < a.size(); ++i )
{
while ( true )
{
std::vector<int>::iterator it;
it = std::find(b.begin(), b.end(), a[i]);
if ( it != b.end() )
{
i = 0; //because of moving elements
b.erase(b.begin()+i);
a.erase(a.begin()+i);
break;
}
}
}
return true;
}
int main(){
vector<int> a;
vector<int> b;
a.push_back(1);
a.push_back(2);
a.push_back(3);
b.push_back(1);
b.push_back(2);
b.push_back(3);
remove(a,b);
return 0;
}
The problem is - the last equal elements stay, so I can't remove them. How can I fix this, taking into consideration that unequal elements can be in the middle of the vector: a = 1, 2, 3; b = 1, 3, 3 -- 2 from vector a and 3 from vector b shouldn't be deleted?

As I understand, when I remove an element, other elements move.
That's partially true. If you remove an element, the elements after it get pushed down to fill the hole. If you remove the 5th element, the element that was the 6th element now becomes the 5th. But the element that was the 4th still stays the 4th. And this is certainly true only after you erase. So your code is:
i = // the element from a
it = // the iterator pointing to an element from b
i = 0;
b.erase(b.begin()+i); // erase the 1st element from b
a.erase(a.begin()+i); // erase the 1st element from a
You do all this work to find a pair of equal elements, and then immediately discard it - erasing the front element of both vectors. That's why it doesn't work. You want to erase the elements that you found:
b.erase(it);
a.erase(a.begin() + i); // no i = 0
Note that if you want to erase every element that has a match in the other array, this fix won't cut it - if you have two 1s in a but ony one in b you'd never remove the second one. For this, we need to take advantage of the Erase-remove idiom:
for (std::vector<int>::iterator itA = a.begin(); itA != a.end(); /* nothing */)
{
std::vector<int>::iterator itB = std::find(b.begin(), b.end(), *itA);
if (itB == b.end()) {
// done with this element, move on
++itA;
}
else {
// erase EVERYTHING
b.erase(std::remove(itB, b.end(), *itA), b.end());
itA = a.erase(std::remove(itA, a.end(), *itA), a.end());
}
}

Related

Keeping values of vector [duplicate]

This question already has answers here:
How to keep only duplicates efficiently?
(10 answers)
Closed 2 years ago.
I'm having trouble with writing a program to keep only duplicates,here is what I already wrote :
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v;
for (int n; std::cin >> n;)
{v.push_back(n); }
std::sort(v.begin(),v.end());
for(std::vector<int>::iterator b = v.begin();b<v.end();++b)
{
if(*b != *(b+1) )
{
v.erase(b);
}
}
for(std::vector<int>::iterator i = v.begin();i < v.end();++i)
{
std::cout<<*i<<" ";
}
}
What I mean by "keep duplicates" is for example
Input: 13 7 2 13 5 2 1 13
Output : 2 13
I apologise if code is not so perfect, I'm complete beginner.I hope you understand my dificulties.
When you erase() from a vector all iterators pointing at the erased element or later in the vector becomes invalidated. Fortunately, erase() returns an iterator to the element that was after the erased element, so you could do:
for(auto b = v.begin(), end=std::prev(v.end()); b != end;) {
if(*b != *(b+1) ) b = v.erase(b);
else ++b;
}
Note that you need to stop iterating one element before end() since you do *(b+1).
The above does however not remove all but one of the repeated elements.
A different approach could be to search for the first element not being part of a repeating sequence and to erase the element if it had no repetitions and to erase all repetitions but one if it had repetitions.
I've used the standard algorithm std::find_if_not in the example below but you can easily replace it with a loop that does that same thing. Just search for the first element not being equal to *b.
#include <algorithm>
for(auto b = v.begin(); b != v.end();) {
// find the first element not being a repetition of *b
auto r = std::find_if_not(b + 1, v.end(), [&b](const auto& v) { return *b==v; });
if(b + 1 == r) b = v.erase(b); // *b had no repetitions, erase b
else b = v.erase(b + 1, r); // erase all repetitions except one element
}
You are trying to dereference an invalid iterator. On the last iteration of your second for loop, *(b+1) will try to dereference this iterator.
Change:
for(std::vector<int>::iterator b = v.begin();b<v.end();++b)
to:
for(std::vector<int>::iterator b = v.begin();b<v.end()-1;++b)
And change your erase to:
v.erase(b+1)
You are trying to erase the iterator in the current iteration.

Sort a vector using a boolean predicate function in O(N) time

As an example, suppose I want to sort the vector {1, 2, 3, 4, 5}, placing even numbers on the left and odd numbers on the right. I can devise an algorithm that does this in O(N) time (shown below). My question is, is there an existing STL algorithm for something like this?
My (not very generic or pretty) solution
#include <iostream>
#include <vector>
/**
Sort a vector of integers according to a boolean predicate function
Reorders the elements of x such that elements satisfying some condition
(i.e. f(x) = true) are arranged to the left and elements not satisfying the
condition (f(x) = false) are arranged to the right
(Note that this sort method is unstable)
#param x vector of integers
*/
void sort_binary(std::vector<int>& x, bool (*func)(int)){
// Strategy:
// Simultaneously iterate over x from the left and right ends towards
// the middle. When one finds {..., false, ..., ..., true, ....},
// swap those elements
std::vector<int>::iterator it1 = x.begin();
std::vector<int>::iterator it2 = x.end();
int temp;
while(it1 != it2){
while(func(*it1) && it1 < it2){
++it1;
}
while(!func(*it2) && it1 < it2){
--it2;
}
if(it1 != it2){
// Swap elements
temp = *it1;
*it1 = *it2;
*it2 = temp;
}
}
}
int main() {
// Sort a vector of ints so that even numbers are on the
// left and odd numbers are on the right
std::vector<int> foo {1, 2, 3, 4, 5};
sort_binary(foo, [](int x) { return x % 2 == 0; } );
for(auto &x : foo) std::cout << x << " ";
}
You can use std::partition()
Reorders the elements in the range [first, last) in such a way that all elements for which the predicate p returns true precede the elements for which predicate p returns false. Relative order of the elements is not preserved.
complexity:
Exactly N applications of the predicate. At most N/2 swaps if ForwardIt meets the requirements of LegacyBidirectionalIterator, and at most N swaps otherwise.
std::partition( foo.begin(), foo.end(), [](int x) { return x % 2 == 0; } );
live example
PS you can use std::stable_partition() if you want to preserve order of the elements

Finding consecutive elements in a vector

I am working on a problem where I have to create subvectors from a bigger vector. If the elements in the vector are consecutive I have to create a vector of those elements. If there are elements which are not consecutive then a vector of that single elements is created. My logic is as below
vector<int> vect;
for (int nCount=0; nCount < 3; nCount++)
vect.push_back(nCount);
vect.push_back(5);
vect.push_back(8);
vector<int>::iterator itEnd;
itEnd = std::adjacent_find (vect.begin(), vect.end(), NotConsecutive());
The functor NotConsecutiveis as below
return (int first != int second-1);
So I am expecting the std::adjacent_find will give me back the iterators such that I can create vector one{0,1,2,3}, vector two{5} and vector{8}. But I am not sure if there is any simpler way?
Edit:I forgot to mention that I have std::adjacent_find in a loop as
while(itBegin != vect.end())
{
itEnd = std::adjacent_find (vect.begin(), vect.end(), NotConsecutive());
vector<int> groupe;
if( std::distance(itBegin, itEnd) < 1)
{
groupe.assign(itBegin, itBegin+1);
}
else
{
groupe.assign(itBegin, itEnd);
}
if(boost::next(itEnd) != vect.end())
{
itBegin = ++itEnd;
}
else
{
vector<int> last_element.push_back(itEnd);
}
}
Does it make any sense?
I think this is what is being requested. It does not use adjacent_find() but manually iterates through the vector populating a vector<vector<int>> containing the extracted sub-vectors. It is pretty simple, IMO.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vect { 0, 1, 2, 3, 5, 8 };
// List of subvectors extracted from 'vect'.
// Initially populated with a single vector containing
// the first element from 'vect'.
//
std::vector<std::vector<int>> sub_vectors(1, std::vector<int>(1, vect[0]));
// Iterate over the elements of 'vect',
// skipping the first as it has already been processed.
//
std::for_each(vect.begin() + 1,
vect.end(),
[&](int i)
{
// It the current int is one more than previous
// append to current sub vector.
if (sub_vectors.back().back() == i - 1)
{
sub_vectors.back().push_back(i);
}
// Otherwise, create a new subvector contain
// a single element.
else
{
sub_vectors.push_back(std::vector<int>(1, i));
}
});
for (auto const& v: sub_vectors)
{
for (auto i: v) std::cout << i << ", ";
std::cout << std::endl;
}
}
Output:
0, 1, 2, 3,
5,
8,
See demo at http://ideone.com/ZM9ssk.
Due to the limitations of std::adjacent_find you can't use it quite the way you want to. However it can still be useful.
What you can do is to iterate over the collection, and use std::adjacent_find in a loop, with the last returned iterator (or your outer loop iterator for the first call) until it returns end. Then you will have a complete set of consecutive elements. Then continue the outer loop from where the last call to std::adjacent_find returned a non-end iterator.
Honestly, I don't find any clear disadvantage of using a simple hand-crafted loop instead of standard functions:
void split(const std::vector<int> &origin, vector<vector<int> > &result)
{
result.clear();
if(origin.empty()) return;
result.resize(1);
result[0].push_back(origin[0]);
for(size_t i = 1; i < origin.size(); ++i)
{
if(origin[i] != origin[i-1] + 1) result.push_back(vector<int>());
result.back().push_back(origin[i]);
}
}

Erasing while iterating an std::list

If I'm using an iterator in a for loop and I use erase on a current iteration of iterator, the for loop should continue fine and access the rest of the list elements?
From what I have read, this should be the case and is a primary distinguishing characteristic of list vs deque or vector. For my purposes, a queue might work but I need this behavior.
Here is the loop I am considering:
std::list<Sequence>::iterator iterator;
iterator=m_concurrents.begin();
for (;iterator!=m_concurrents.end();++iterator){
if (iterator->passes()){
m_concurrents.erase(iterator);
}
}
The idiomatic way to write that loop would be:
for (auto i = list.begin(); i != list.end();) {
if (condition)
i = list.erase(i);
else
++i;
}
You can do the same thing with a set, multiset, map, or multimap. For these containers you can erase an element without affecting the validity to any iterators to other elements. Other containers like vector or deque are not so kind. For those containers only elements before the erased iterator remain untouched. This difference is simply because lists store elements in individually allocated nodes. It's easy to take one link out. vectors are contiguous, taking one element out moves all elements after it back one position.
Your loop is broken because you erase the element at i on some given condition. i is no longer a valid iterator after that call. Your for loop then increments i, but i is not valid. Hell upon earth ensues. This is the exact situation that is why erase returns the iterator to the element after what was erased... so you can continue traversing the list.
You could also use list::remove_if:
list.remove_if([](auto& i) { return i > 10; });
In the lambda, return true if the element should be removed. In this example, it would remove all elements greater than 10.
for (auto i = list.begin(); i != list.end(); ++i) {
if (condition) {
list.erase(i);
--i;
}
}
If you just want to use for iterator, you can use it this way, for example:
list<int> lst{4, 1, 2, 3, 5};
for(auto it = lst.begin(); it != lst.end();++it){
if ((*it % 2) == 1){
it = lst.erase(it); erase and go to next(erase will return the next iterator)
--it; // as it will be add again in for, so we go back one step
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
But erase in while iterator will be more clear:
list<int> lst{4, 1, 2, 3, 5};
auto it = lst.begin();
while (it != lst.end()){
if((*it % 2) == 1){
it = lst.erase(it);// erase and go to next
} else{
++it; // go to next
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
You can also use member function remove_if:
list<int> lst{4, 1, 2, 3, 5};
lst.remove_if([](int a){return a % 2 == 1;});
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
Or use std::remove_if conbine with erase funtion:
list<int> lst{4, 1, 2, 3, 5};
lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){
return a % 2 == 1;
}), lst.end());
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
You can also reference to this question:
Removing item from vector, while in C++11 range 'for' loop?

While Loop Error

I have an assignment to merge two sorted vectors into a third sorted vector. I'm sure the solution to this problem is pretty simple, but my brain is fried at the moment and could use your help.
Basically vectors A and B have a size of 3. They will hold integers such as 1, 2, 3 and 4, 5, 6 respectively. I can't seem to get the syntax of my while loop correctly. I've tried making it a do/while loop, putting parentheses around the cases, and a few other things. It just doesn't seem to be reading the part after the &&.
The first for loop just makes the R vector have the right size. And the second for loop just displays the values of the R vector. The result should print out from 1-6, but I'm only seeing 1-3.
Any help would be appreciated!
void::combine(vector<int> A, vector<int> B, vector<int> R) {
int ia = 0, ib = 0, ir = 0;
for (int i = 0; i < A.size() + B.size(); i++) {
R.push_back(0);
}
while (ia != A.size() && ib != B.size()) {
if (A[ia] < B[ib]) {
R[ir] = A[ia];
ia += 1;
}
else {
R[ir] = B[ib];
ib += 1;
}
ir += 1;
}
for (int i = 0; i < R.size(); i++) {
cout << "L3[" << i << "] = " << R[i] << endl;
}
}
Assuming A contains [1,2,3] and B contains [4,5,6] as you say, this will not add any of the element in the B vector to the R vector.
This is because on the 4th iteration, ia == 3, and so the conjunctive condition is no longer true..
Try changing it to while(ia != A.size() || ib != B.size())
Probably you should avoid the loop altogether:
void combine(vector<int> const& A, vector<int> const& B, vector<int> & R) {
R.resize( A.size() + B.size() );
std::copy( A.begin(), A.end(), R.begin() );
std::copy( B.begin(), B.end(), R.begin()+A.size() );
std::sort( R.begin(), R.end() );
for ( int i = 0; i < R.size(); ++i )
{
cout << "L3[" << i << "] = " << R[i] << endl;
}
}
This is suboptimal as you are first copying and then ordering, but for a small size it will have no impact.
On the actual issues with your code: try to avoid pass-by-value, use resize instead of multiple push_back() to fix the size (note that if the R argument to your function was a non-empty vector then the final size would be bigger than you want). Consider using a return value instead of a reference argument --easier to read. You looped until the first of the counters reached the end, but left the rest of the elements in the other container without copying.
A manual implementation, using iterators would also be simpler:
typedef std::vector<int> vector_t;
vector_t combine( vector_t const & a, vector_t const & b ) {
vector_t r( a.size() + b.size() ); // [*]
vector_t::const_iterator ita = a.begin(), enda = a.end();
vector_t::const_iterator itb = b.begin(), endb = b.end();
vector_t::iterator itr = r.begin();
while ( ita != enda && itb != endb ) {
if ( *ita < *itb )
*itr++ = *ita++;
else
*itr++ = *itb++;
}
if ( ita != enda )
std::copy( ita, enda, itr );
else
std::copy( itb, endb, itr );
return r;
}
I don't know what you're trying to do in the while loop. But if you're just populating the vector R with the elements in A and B, without giving any regard to the order how they're added, then you can use insert function, as:
void::combine(const vector<int> &A, const vector<int> &B, vector<int>& R)
{
R.insert(R.end(), A.begin(), A.end());
R.insert(R.end(), B.begin(), B.end());
}
And if you want to order the vector R, then you can add the following line to the above function:
sort( R.begin(), R.end()); //sorts in increasing order.
You've to #include<algorithm> if you do so. If you want to sort in decreasing order then do this:
bool compare( int a, int b ) { return a > b; }
sort( R.begin(), R.end(), compare); //sorts in decreasing order.
First of all, this smells like a classic merge sort or a piece of it:
http://en.wikipedia.org/wiki/Merge_sort
The objective is to examine elements of the first vector, A, to elements of vector B, and append the elements to a resulting vector R, in order.
Thus if A[i] < B[j], append A[i] to R. With std::vector, there is no need to load the result vector with zeros before starting. See std::vector::push_back().
The following is untested code:
void Sort_Vector(const std::vector& A, const std::vector& B, std::vector& result)
{
unsigned int index_a = 0; // Point to first element in first vector.
unsigned int index_b = 0; // Point to first element in second vector.
result.clear(); // Clear all elements, so size == 0.
while ((index_a < A.size()) && (index_b < B.size())
{
if (A[index_a] < B[index_b])
{
result.push_back(A[index_a]);
++index_a;
}
else // B[index_b] <= A[index_a]
{
result.push_back(B[index_b]);
++index;
}
}
// Append any remaining elements to the result vector.
// Only one of the two loops should be executed,
// the other will fail the comparison expression
// and not execute.
for (; index_a < A.size(); ++index_a)
{
result.push_back(A[index_a]);
}
for (; index_b < B.size(); ++index_b)
{
result.push_back(B[index_b]);
}
return;
}
Notice the difference between my function's signature (parameters) and yours. I'm passing the source vectors as constant data and the result vector is passed by reference which enables my function to modify the caller's result vector.
Also, I'm lazy and using the std::vector::push_back() method. I believe this is more readable than assigning to an element in the result vector. The push_back method implies that I am appending to the vector. The assignment route may catch readers off-guard if they forget that a vector will expand in order resolve the assignment.
that's because of your && condition. as soon as ia == A.size(), the first part of the condition (ia != A.size()) will always evaluate to false and the ib part of your loop won't execute.
to fix it, you can change the condition to : (iA < A.size()) || (iB < B.size())
e.g. with 123 and 456 what is being done right now.
Initialize R to {0,0,0,0,0,0}
until all values from one vector are inserted into R compare candidates and insert smaller one into R, get next candidate from winner list.
and that's all - I don't know that is the purpose of the function if you'll write it I/We can provide solution otherwise just review 2nd point in above form.
The syntax is fine (the code wouldn't compile otherwise), but your loop condition isn't. Given your example A = { 1, 2, 3 } and B = { 4, 5, 6 }, the loop will enter the A[ia] < B[ib] branch three times and increment ia to 3. Once this happens, the first part of the loop condition, ia != A.size() won't be true, and so the loop ends.
Since you already know how many items you need to place in the result vector, I'd recommend replacing your while loop with a simple for one with the same body.