Removing duplicate elements in using the function "remove" - c++

I tried to remove duplicate elements from a vector by a function vectorremove, using the function remove from the library of algorithms, but it does not work:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
void vectorremove(vector<string> v)
{
for (vector<string>::iterator it = v.begin(); it != v.end(); ++it)
{
vector<string>::iterator end = remove(it + 1, v.end(), *it);
v.erase(end, v.end());
}
}
int main()
{
vector<string> vect;
string x;
while (cin >> x)
{
vect.push_back(x);
}
vectorremove(vect);
for (vector<string>::iterator it = vect.begin(); it != vect.end(); ++it)
{
cout << *it << endl;
}
return 0;
}
I wrote this code to test if the function vectorremove works, unfortunately it seems that vectorremove has no impact on the vector. Have I made any mistake in the use of remove in the definition of vectorremove?

The first problem in your code is that you are passing the vector by value and not by reference to vectorremove. You need to change that to
void vectorremove(vector<string>& v);
Then inside your vectorremove function you have another problems. vector::erase can invalidate all iterators, so you should onle remove inside the loop and do the erase after the loop.
void vectorremove(vector<string>& v)
{
vector<string>::iterator end{ v.end() };
for (vector<string>::iterator it = v.begin(); it != end; ++it)
{
end = remove(it + 1, end, *it);
}
v.erase(end, v.end());
}

First you are passing std::vector by value, not by reference. Therefore, any changes you make in vectorremove function won't be visible in main.
Furthermore, std::vector::erase might invalidate iterators so you must not use it inside the loop.
Your code could look like:
void vectorremove(std::vector<std::string>& v) {
auto end{ v.end() };
for (auto it = v.begin(); it != end; ++it)
{
end = std::remove(it + 1, end, *it);
}
v.erase(end, v.end());
}
Note the usage of auto instead of std::vector<std::string>::iterator.
However, STL provides handy functions to achieve what you want. One of them is std::unique which
Eliminates all but the first element from every consecutive group of
equivalent elements from the range [first, last) and returns a
past-the-end iterator for the new logical end of the range.
In order to remove duplicates from the std::vector, you can do something like:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v{ 1, 2, 3, 1, 2, 3, 3, 4, 5, 4, 5, 6, 7 };
std::sort(v.begin(), v.end()); // 1 1 2 2 3 3 3 4 4 5 5 6 7
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end());
for (auto const i : v) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
Remember that std::unique works as expected only on sorted std::vectors.

You only modify the copy of vector , you have to pass by reference to modify the actual
vector, why you don't use auto instead of std::vector::iterator. and you have to
know that erase invalidates all iterators pointing to the erased element and
beyond the erased element, keep the iterator valid by using erase's return value, also use std::getline inside the loop to store the value from std::cin to include the new line.
Alternatively your can use std::unique removes the duplicate value and works as expected after sorting the elements. and std::unique returns a past the end iterator for the new logical end of the range:-
#include <vector>
#include <algorithm>
#include <string>
std::vector<std::string> removeDuplicate(std::vector<std::string> & v){
std::vector<std::string> vec;
std::sort(std::begin(v), std::end(v));
auto pos = std::unique(std::begin(v), std::end(v));
vec.assign(std::begin(v), pos);
return vec;
}
int main(){
std::vector<std::string> vect{"John", "John", "Paul", "John", "Lucy", "Bob", "Bob"};
auto pureVector = removeDuplicate(vect);
for(auto const & v : pureVector){
std::cout << v << '\n';
}
}

Related

How can I print a vector in a recursive function?

I have a problem here: I am to write a function that prints the elements of a vector recursively so no loop is allowed.
I tried this code but it crashes at runtime:
void print(const std::vector<int> ivec, std::vector<int>::const_iterator it) {
if (it == ivec.end())
return;
std::cout << *it++ << std::endl;
print(ivec, it);
}
int main(){
vector<int> v{
5, 7, 77, 23, 10, 81
};
print(v, v.begin());
}
If I run the program I get the assertion dialog!?
void print(const std::vector<int> ivec, std::vector<int>::const_iterator it) {
The ivec parameter is passed by value. Both of these parameters are passed by value. Passing by value by means that inside the function these are copies of the original parameters.
Your main() calls this recursive function passing it its vector and the beginning iterator of its vector. However because all parameters are passed by value, each recursive iteration of the function compares the iterator to the end() of a completely different vector. Undefined behavior.
You obviously forgot to pass the vector by reference. The first parameter to should be const std::vector<int> &ivec.
When you call print, you pass the vector by value. This means that it creates an entirely new vector each time, but the iterator still comes from the original vector. Because the iterator comes from a different vector, the test it == ivec.end() is always going to fail.
We can fix this just by passing ivec by const reference:
void print(const std::vector<int>& ivec, std::vector<int>::const_iterator it)
{
if (it == ivec.end())
return;
std::cout << *it++ << std::endl;
print(ivec, it);
}
And the code works fine!
You have to pass the vector by reference so that to avoid multiple copies thus the iterator is guaranteed to be compared with the iterators of the same vector only not with others':
void print(const std::vector<int>& ivec, std::vector<int>::const_iterator it) {
if (it == ivec.end())
return;
std::cout << *it++ << std::endl;
print(ivec, it);
}
int main(){
vector<int> v{
5, 7, 77, 23, 10, 81
};
print(v, v.begin()); // ok
vector<int>::iterator it = v.begin();
auto v2{ v };
if (it == v.begin())
cout << "it = v.begin()" << endl;
if (it == v2.begin()) // causes crash
cout << "it =v2.begin()" << endl;
}
No need to pass in two arguments to the print function. If the vector is zero-length, print nothing.
if the vector is length of 1, print that element.
if the vector is of length greater than 1, then print a smaller vector (recursively) that does not include the last character, and then print the last character.
yes, this will create a copy of the vector for each recursion, but I guess that feels more like recursion to me. Incrementing a pointer on each loop does not feel like recursion.
#include <iostream>
#include <vector>
void print(const std::vector<int> vec) {
if (!vec.size())
return;
else {
print(std::vector<int>(vec.begin(), vec.end() - 1));
std::cout << " " << *(vec.end() - 1);
}
}
int main(){
std::vector<int> v{
5, 7, 77, 23, 10, 81
};
print(v);
}
If you just need to print the vector, I think a much more elegant solution would be to use iterators.
#include <iostream>
#include <vector>
using namespace std;
void print_vector(vector<int>::iterator it, const vector<int>::iterator &end)
{
if(it == end) {
cout << '\n';
return;
}
cout << *it << " ";
print_vector(++it, end);
}
int main() {
vector<int> v = {1,2,3,4,5,6,7,8,9};
print_vector(v.begin(), v.end());
return 0;
}
If you want to reuse the function with other structures (perhaps to impress a friend or a teacher) you can use the templates.
#include <iostream>
#include <set>
#include <vector>
using namespace std;
template<class TContainer>
void print_structure(typename TContainer::iterator it, const typename TContainer::iterator end)
{
if(it == end) {
cout << '\n';
return;
}
cout << *it << " ";
print_structure<TContainer>(++it, end);
}
int main() {
vector<int> vi = {1,2,3,4,5,6,7,8,9};
print_structure<vector<int>>(vi.begin(), vi.end());
vector<double> vd = {1.2, 3.4, 5.6, 7.8, 9.0};
print_structure<vector<double>>(vd.begin(), vd.end());
set<int> si = {10, 10, 10, 10, 20, 20, 20, 20, 30, 30, 30};
print_structure<set<int>>(si.begin(), si.end());
set<double> sd = {10.10, 10.10, 20.20, 20.20, 30.30, 3.0};
print_structure<set<double>>(sd.begin(), sd.end());
return 0;
}
Does it look like a bazooka to kill mosquitoes? Sure it is! But it's pretty crazy yeah?!

Is there a way to iterate over two containers without using two for loops

Is there a way to iterate over two containers (one followed by the other), without using two for loops.
My intention is to do something like this
vector<int> a{ 1,2,3 };
vector<int> b{ 4,5,6 };
auto it = a.begin();
auto end = b.end();
for (; it != end; ++it)
{
if (it == a.end())
{
it = b.begin();
}
// do something with *it
}
to print
1 2 3 4 5 6
(of course it doesn't work. The explanation is in this answer )
I do not want to write two for loops and duplicate the code inside the loop.
Is there a way to iterate over a followed by b with a single for loop?
The only thing I can think of is either copy/move the second container to the first or create a new vector combining a and b, and then iterate over it. I do not want to do this either, because this will mean expensive copy operations.
Using range-v3, your go-to for all things range-related in C++17 or earlier:
for (int i : view::concat(a, b)) {
std::cout << i << ' ';
}
one more way to do it using boost range
#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/join.hpp>
int main()
{
std::vector<int> a{ 1,2,3 };
std::vector<int> b{ 4,5,6 };
for(auto& x : boost::join(a, b)) {
std::cout << x << " ";
}
std::cout << std::endl;
}
Boost Range and Standard Library algorithms are solutions which should be prefered because of their better design.
However, just for sake of completeness, if you really want to apply the idea behind your design you can code like the following:
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {4, 5, 6};
for (auto it = v1.begin(); it != v2.end();) {
if (it == v1.end()) {
it = v2.begin();
} else {
// {
// use of *it
// }
++it;
}
}
Live Demo Here
You can use boost::range::join like so:
#include <boost/range/join.hpp>
...
std::vector<int> a{ 1,2,3 };
std::vector<int> b{ 4,5,6 };
for (auto i : boost::range::join(a, b))
{
...
}
Found an easy 'traditional' way to do this.
for (int i = 0; i < 2; i++)
{
auto it = (i == 0) ? a.begin() : b.begin();
auto end = (i == 0) ? a.end() : b.end();
for (; it != end; ++it)
{
// do something with *it
}
}
If you feel like writing your own, the following helps:
template<class ForwardItr>
struct range {
ForwardItr beg;
ForwardItr end;
};
template<class ForwardItr, class F>
void concat_ranges(range<ForwardItr> r1, range<ForwardItr> r2, F f) {
auto run = [&f](range<ForwardItr> r) {
for(auto itr = r.beg; itr != r.end; ++itr){
f(*itr);
}
};
run(r1);
run(r2);
};
Example: https://gcc.godbolt.org/z/8tPArY
Not even a single for() loop requires to print these container, If you use std::copy as follows,
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main(int , char *[])
{
std::vector< int> a{ 1, 2, 3};
std::vector< int> b{ 4, 5, 6};
std::copy( a.begin(), a.end(), std::ostream_iterator< int>( std::cout, " "));
std::copy( b.begin(), b.end(), std::ostream_iterator< int>( std::cout, " "));
std::cout<< std::endl;
return 0;
}
output : 1 2 3 4 5 6
Using stl library is best option and it is not required to write any code to print a container.
As per your concern I do not want to write two for loops and duplicate the code inside the loop. Is there a way to iterate over a followed by b with a single for loop?
The way to avoiding duplicate code is write functions which can be used from multiple places, for example if you don't want to use std::copy and wants to write your own code to print these containers (which is not recommended) then you can write following function,
template< typename ForwardIterator>
void print( ForwardIterator begin, ForwardIterator end, const std::string& separator)
{
while( begin != end)
{
std::cout<< *begin<< separator;
++begin;
}
}
then call print function,
print( a.begin(), a.end(), std::string( " "));
print( b.begin(), b.end(), std::string( " "));
Well... your error is a double equal where you need a single equal.
I mean, not
if (it == a.end())
{
it == b.begin();
} // ^^ Wrong!
but
if (it == a.end())
{
it = b.begin();
} // ^ correct
But I don't think it's a good idea: we are sure that a.end() != b.end() ?
Your code depend from this.
To get the most optimal code it is preferable to avoid to make unnecessary test at each loop. Since the most efficient code consist in performing two loops, it is possible to get close to that by changing the entire state of the variables that participate in the loop (iterator and sentinel), (I suppose this is how is implemented a concatenated range ... this is how I did):
vector<int> a{ 1,2,3 };
vector<int> b{ 4,5,6 };
auto it = a.begin();
auto end = a.end();
for (;[&](){
if (it==end){
if (end==a.end()) {
it=b.begin();
end=b.end();
return true;
}
else return false;
}
return true;
}();
++it)
{
//loop content
}

How to erase elements in STL vector without copying iterator and without memory leakage?

This is the edited code
vector<vector<int> > vec;
vector<vector<int> >::iterator vit;
vector<int>::iterator it;
for ( vit = vec.begin(); vit != vec.end(); ++vit)
{
it = vit->begin();
while(it != vit->end())
{
while(it != vit->end())
{
if( condition )
{
while( condition )
{
//going back to certain it
//erase an element
it = vit->erase(it);
}
}
else
++it;
}
++it;
}
}
The inner while loops back to certain point. Link missing.
Erasing element without copying iterator and without memory leakage in back loop and again forward?
If you want to remove certain elements of the inner vectors use the erase-remove idiom on them:
for (auto & intv : vec)
{
intv.erase(
std::remove_if( intv.begin(), intv.end(),
[](int value) -> bool { return value == 2; }),
intv.end() );
}
Notes:
You can apply certain conditions depending on vec or other local variables by capturing them in the lambda expression.
This example would remove all elements from the inner vectors that are equal to 2.
For int it is preferable to pass the lambda paramter by value. For bigger objects you'd probably want to have a const reference lambda paramter.
You can use the erase-remove idiom for that purpose.
Simple example:
#include <iostream>
#include <vector>
#include <algorithm>
bool is_odd(const int &i)
{
return (i % 2) != 0;
}
int main()
{
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// removes all odd numbers
v.erase(std::remove_if(v.begin(), v.end(), is_odd), v.end());
for(const auto &i:v)
{
std::cout << i << ' ';
}
return 0;
}
Of course you can achieve the same thing using a lambda like this:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// removes all odd numbers
v.erase( std::remove_if(v.begin(), v.end(),
[](const int &i) -> bool {return (i % 2) != 0;}),
v.end() );
for(const auto &i:v)
{
std::cout << i << ' ';
}
return 0;
}
You can use STL vector's erase function. Just use vector.remove(*it) to remove the element
You dont need to worry about memory leaks, in your case you use std::vector which uses RAII to make sure no memory is leaked. With STL containers you can "leak" in such case on;y if you do not shrink your vector after using remove algorithm.
Below is fix to your code, and not entire rewrite. This code removes all values equal to 1 [LIVE]:
vector<vector<int> > vec = { {0,1,2,3}, {0,1,2,3,4,5}, {0,1} };
vector<vector<int> >::iterator vit = vec.begin();
vector<int>::iterator it;
while(vit != vec.end()) {
it = vit->begin();
while(it != vit->end()) {
if( *it == 1 ) {
it = vit->erase(it);
// Not sure why you want this loop here
//while( condition )
//{
// **erase an element;**
//}
}
else {
++it;
}
}
++vit;
}
for (auto it1 = vec.begin(); it1 != vec.end(); ++it1){
for (auto it2 = it1->begin(); it2 != it1->end(); ++it2)
std::cout<<*it2<< ", ";
std::cout << "\n";
}
produces:
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
0, 2, 3,
0, 2, 3, 4, 5,
0,

c++11 insert a vector into a particular position

I am using c++11, I like to insert a vector into a particular position of another vector, here is a simplified code:
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v1 = {1, 2, 3};
vector<int> v2 = {0, 3, 9};
vector<int>::iterator itr = find(v2.begin(), v2.end(), 3);
itr = v2.erase(itr);
// like to insert "3", "2" and "1" to the same position which ends up "1", "2" and "3"
for (auto ri = v1.rbegin(); ri != v1.rend(); ++ri) {
v2.insert(itr, *ri);
}
for (const auto &i : v2) {
cout << i << " ";
}
cout << endl;
return 0;
}
The above code crashes.
Yes, I know some other STL API like transform() or copy() might be the one to use, but just wonder what is wrong of the above code?
Your current code crashes because itr is invalidated when insert() reallocates v2 after it exceeds its max capacity.
Change the following:
v2.insert(itr, *ri);
to
itr = v2.insert(itr, *ri);
Use this API
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);
So in your case, replace the second loop with:
insert(itr,v2.begin(),v2.end())
what is wrong of the above code?
The iterator itr became invalid after insert, so program crashed at the 2nd execution of the for loop. You can use the return value of insert (iterator pointing to the inserted value) to get a valid iterator for insert position.
Change
v2.insert(itr, *ri);
to
itr = v2.insert(itr, *ri);
insert causes reallocation if the new size() is greater than the old capacity(). If the new size() is greater than capacity(), all iterators and references are invalidated. Otherwise, only the iterators and references before the insertion point remain valid. The past-the-end iterator is also invalidated.
Reference: http://en.cppreference.com/w/cpp/container/vector/insert
PS: Please see #Kam's answer, it's a better solution than hand-written loops in general cases.

Remove an element from a vector by value - C++

If I have
vector<T> list
Where each element in the list is unique, what's the easiest way of deleting an element provided that I don't know if it's in the list or not? I don't know the index of the element and I don't care if it's not on the list.
You could use the Erase-remove idiom for std::vector
Quote:
std::vector<int> v;
// fill it up somehow
v.erase(std::remove(v.begin(), v.end(), 99), v.end());
// really remove all elements with value 99
Or, if you're sure, that it is unique, just iterate through the vector and erase the found element. Something like:
for( std::vector<T>::iterator iter = v.begin(); iter != v.end(); ++iter )
{
if( *iter == VALUE )
{
v.erase( iter );
break;
}
}
Based on Kiril's answer, you can use this function in your code :
template<typename T>
inline void remove(vector<T> & v, const T & item)
{
v.erase(std::remove(v.begin(), v.end(), item), v.end());
}
And use it like this
remove(myVector, anItem);
If occurrences are unique, then you should be using std::set<T>, not std::vector<T>.
This has the added benefit of an erase member function, which does what you want.
See how using the correct container for the job provides you with more expressive tools?
#include <set>
#include <iostream>
int main()
{
std::set<int> notAList{1,2,3,4,5};
for (auto el : notAList)
std::cout << el << ' ';
std::cout << '\n';
notAList.erase(4);
for (auto el : notAList)
std::cout << el << ' ';
std::cout << '\n';
}
// 1 2 3 4 5
// 1 2 3 5
Live demo
From c++20
//LIKE YOU MENTIONED EACH ELEMENT IS UNIQUE
std::vector<int> v = { 2,4,6,8,10 };
//C++20 UNIFORM ERASE FUNCTION (REMOVE_ERASE IDIOM IN ONE FUNCTION)
std::erase(v, 8); //REMOVES 8 FROM VECTOR
Now try
std::erase(v, 12);
Nothing will happen, the vector remains intact.