unique operation

Nov 14, 2016 at 3:30am
Dear all,

I am trying to figure out some operations of algorithm in C++. One of them is unique and its return value. Quoting from cplusplus.com:
An iterator to the element that follows the last element not removed.
The range between first and this iterator includes all the elements in the sequence that were not considered duplicates.

To check it, I wrote a script in C++ as following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <iomanip>
#include <algorithm> //unique
#include <vector>
using namespace std;
/*
Function declaration
*/
template <class T>
void print(const vector<T>& vrr); // print vector of T
/*
Main function
*/
int main() {

    int arr[]={1,2,2,2,1,1};
    vector<int> vrr(arr,arr+5);
    vector<int>::iterator pt1;
    cout<<"The original vector:"<<endl;
    print(vrr);
    // unique
	cout<<"-------------------------------------------------------"<<endl;
    pt1=unique(vrr.begin(),vrr.end());
    cout<<"The modified vector:"<<endl;
    vrr.resize(pt1-vrr.begin()+1);
    print(vrr);
}
/*
Function definition
*/
template <class T>
void print(const vector<T>& vrr){
	typename vector<T>::const_iterator it;
	cout<<"{";
	for(it=vrr.begin();it!=vrr.end();++it){
		cout<<setw(2)<<*it;
		if (it!=vrr.end()-1) cout<<",";
	}
	cout<<"}"<<endl;
}


The output is:
The original vector:
{ 1, 2, 2, 2, 1}
-------------------------------------------------------
The modified vector:
{ 1, 2, 1, 2}

Actually, it is not as expected. I think the expected result must be:
{1,2,1}.

I would be very appreciated if you can explain to me the reason of this strangeness.

Thank you.
Last edited on Nov 14, 2016 at 3:31am
Nov 14, 2016 at 4:08am
The right way to do std::unique is:

1. first std::sort the container - because std::unique checks two consecutive elements for equivalence; if you have two equivalent elements that are not consecutive, the latter won’t be removed.
2. then std:: unique
3. finally std::erase because std::unique doesn't actually remove the elements, instead they are copied to the end

http://stackoverflow.com/questions/1041620/whats-the-most-efficient-way-to-erase-duplicates-and-sort-a-vector
Nov 14, 2016 at 4:10am
You can use std::set to filter out the duplicate values.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <vector>
#include <set>

using namespace std;

void print(const vector<int> &vrr);

int main() 
{
	int i;
	int arr[] = {1,2,2,2,1,1};
	vector<int> vrr(arr, arr+5);

	cout << "The original vector : "; print(vrr);

	set<int> vrr_unique;
	for(i = 0; i < vrr.size(); i++) vrr_unique.insert(vrr[i]);

	vrr.clear(); 
	for(set<int>::iterator it = vrr_unique.begin(); it != vrr_unique.end(); it++) vrr.push_back(*it);

	cout << "The result vector : "; print(vrr);

	return 0;
}

void print(const vector<int> &vrr)
{
	int i;
	for(i = 0; i < vrr.size(); i++)
	{
		cout << vrr[i]; 
		if(i != vrr.size() - 1) cout << ", ";
	}
	cout << endl;
}


The original vector : 1, 2, 2, 2, 1
The result vector : 1, 2

http://cpp.sh/3rzva
Last edited on Nov 14, 2016 at 4:11am
Nov 14, 2016 at 4:51am
Thank you for you explanations. I've got the point: The return value is
An iterator to the element that follows the last element not removed.
The range between first and this iterator includes all the elements in the sequence that were not considered duplicates.
.

Therefore I the resize() member function I should have set pt1-vrr.begin() instead of pt1-vrr.begin()+1. Using distance(vrr.begin(),pt1) is also an option for it.

Best regards!
Nov 14, 2016 at 5:16am
OP: Did you try out first what you've just proposed? I don't think so, otherwise you'd have seen that the modified vector is now {1, 2, 1}.
You'd either have to use a set as Handoro said or sort the vector first as I did
Nov 14, 2016 at 7:26am
Yes. I tried the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <iomanip>
#include <algorithm> //unique
#include <vector>
using namespace std;
/*
Function declaration
*/
template <class T>
void print(const vector<T>& vrr); // print vector of T
/*
Main function
*/
int main() {

    int arr[]={1,2,2,2,1,1};
    vector<int> vrr(arr,arr+5);
    vector<int>::iterator pt1;
    cout<<"The original vector:"<<endl;
    print(vrr);
    // unique
	cout<<"-------------------------------------------------------"<<endl;
    pt1=unique(vrr.begin(),vrr.end());
    cout<<"The modified vector:"<<endl;
    vrr.resize(pt1-vrr.begin());
    print(vrr);
}
/*
Function definition
*/
template <class T>
void print(const vector<T>& vrr){
	typename vector<T>::const_iterator it;
	cout<<"{";
	for(it=vrr.begin();it!=vrr.end();++it){
		cout<<setw(2)<<*it;
		if (it!=vrr.end()-1) cout<<",";
	}
	cout<<"}"<<endl;
}


And the output is what I expected:


The original vector:
{ 1, 2, 2, 2, 1}
-------------------------------------------------------
The modified vector:
{ 1, 2, 1}


The unique operation will work by the following sequence:
{ 1, 2, 2, 2, 1}
-> { 1, 2, 2, 2, 1}
-> { 1, 2, 2, 1}
-> { 1, 2, 1}

Thank you.
Topic archived. No new replies allowed.