C++ Algorithm unique
The unique function in C++ Algorithm is employed to modify a sequence so that every duplicate consecutive element is transformed into a distinct element.
The initial iteration employs the operator== for element comparison, while the subsequent iteration utilizes the provided binary predicate pred.
Syntax
equality (1) template <class ForwardIterator>
ForwardIterator unique (ForwardIterator first, ForwardIterator last);
predicate (2) template <class ForwardIterator, class BinaryPredicate>
ForwardIterator unique (ForwardIterator first, ForwardIterator last,
BinaryPredicate pred);
Parameter
A forward iterator indicates the location of the initial element within the range that will undergo duplicate elimination.
The last parameter is a forward iterator that points to the position immediately after the last element in the range that will be scanned for removing duplicates.
A custom predicate function object is defined by the user to specify the criteria for considering two elements within a range as equivalent. A binary predicate operates on two arguments and evaluates to true if the condition is met, and false if it is not.
Return value
A forward iterator pointing to the updated end of the range[first, last) where consecutive duplicates have been eliminated.
Complexity
The complexity increases linearly within the specified range [first, last) by comparing each consecutive pair of elements and executing assignment operations on some of them.
Data races
The elements within the range [first, last) are accessed and can be altered if necessary.
Exception safety
This function throws an exception if any of pred, the element comparisons, the element assignments or the operations on iterator throws an exception.
Note: The invalid parameters cause an undefined behavior.
Example 1
Let's explore a straightforward example to illustrate the functionality of the unique method:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cctype>
using namespace std;
int main()
{
// remove duplicate elements
vector<int> v{1,2,3,1,2,3,3,4,5,4,5,6,7};
sort(v.begin(), v.end());
auto last = unique(v.begin(), v.end());
// v now holds {1 2 3 4 5 6 7 x x x x x x}, where 'x' is indeterminate
v.erase(last, v.end());
for (int i : v)
cout << i << " ";
cout << "\n";
return 0;
}
Output:
1 2 3 4 5 6 7
Example 2
Let's see another simple example:
#include <iostream> // std::cout
#include <algorithm> // std::unique, std::distance
#include <vector> // std::vector
using namespace std;
bool myfunction (int i, int j) {
return (i==j);
}
int main () {
int myints[] = {10,20,20,20,30,30,20,20,10}; // 10 20 20 20 30 30 20 20 10
vector<int> myvector (myints,myints+9);
// using default comparison:
vector<int>::iterator it;
it = unique (myvector.begin(), myvector.end()); // 10 20 30 20 10 ? ? ? ?
// ^
myvector.resize( distance(myvector.begin(),it) ); // 10 20 30 20 10
// using predicate comparison:
unique (myvector.begin(), myvector.end(), myfunction); // (no changes)
// print out content:
std::cout << "myvector contains:";
for (it=myvector.begin(); it!=myvector.end(); ++it)
cout << ' ' << *it;
cout << '\n';
return 0;
}
Output:
myvector contains: 10 20 30 20 10
Example 3
Let's see another simple example:
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
void print(const char* tag, const vector<int>& v) {
cout << tag << " : ";
bool first = true;
for (int x : v) {
if (first) {
first = false;
}
else {
cout << ',';
}
cout << x;
}
cout << endl;
}
int main() {
{
vector<int> v = { 2,5,3,3,1,2,4,2,1,1,4,4,3,3,3 };
decltype(v)::iterator result = unique(v.begin(), v.end());
v.erase(result, v.end());
print("unsorted unique", v);
}
{
vector<int> v = { 2,5,3,3,1,2,4,2,1,1,4,4,3,3,3 };
sort(v.begin(), v.end());
decltype(v)::iterator result = unique(v.begin(), v.end());
v.erase(result, v.end());
print("sorted unique", v);
}
}
Output:
unsorted unique : 2,5,3,1,2,4,2,1,4,3
sorted unique : 1,2,3,4,5
Example 4
Let's see another simple example:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cctype>
using namespace std;
int main()
{
// remove duplicate elements (normal use)
vector<int> v{1,2,3,1,2,3,3,4,5,4,5,6,7};
sort(v.begin(), v.end()); // 1 1 2 2 3 3 3 4 4 5 5 6 7
auto last = unique(v.begin(), v.end());
// v now holds {1 2 3 4 5 6 7 x x x x x x}, where 'x' is indeterminate
v.erase(last, v.end());
for (int i : v)
cout << i << " ";
cout << "\n";
// remove consecutive spaces
string s = "wanna go to space?";
auto end = unique(s.begin(), s.end(), [](char l, char r){
return isspace(l) && isspace(r) && l == r;
});
// s now holds "wanna go to space?xxxxxxxx", where 'x' is indeterminate
cout << string(s.begin(), end) << '\n';
}
Output:
1 2 3 4 5 6 7
wanna go to space?
Example 5
Let's see another example:
#include <vector>
#include <algorithm>
#include <functional>
#include <iostream>
#include <ostream>
using namespace std;
// Return whether modulus of elem1 is equal to modulus of elem2
bool mod_equal ( int elem1, int elem2 )
{
if ( elem1 < 0 )
elem1 = - elem1;
if ( elem2 < 0 )
elem2 = - elem2;
return elem1 == elem2;
};
int main( )
{
vector <int> v1;
vector <int>::iterator v1_Iter1, v1_Iter2, v1_Iter3,
v1_NewEnd1, v1_NewEnd2, v1_NewEnd3;
int i;
for ( i = 0 ; i <= 3 ; i++ )
{
v1.push_back( 5 );
v1.push_back( -5 );
}
int ii;
for ( ii = 0 ; ii <= 3 ; ii++ )
{
v1.push_back( 4 );
}
v1.push_back( 7 );
cout << "Vector v1 is ( " ;
for ( v1_Iter1 = v1.begin( ) ; v1_Iter1 != v1.end( ) ; v1_Iter1++ )
cout << *v1_Iter1 << " ";
cout << ")." << endl;
// Remove consecutive duplicates
v1_NewEnd1 = unique ( v1.begin ( ) , v1.end ( ) );
cout << "Removing adjacent duplicates from vector v1 gives\n ( " ;
for ( v1_Iter1 = v1.begin( ) ; v1_Iter1 != v1_NewEnd1 ; v1_Iter1++ )
cout << *v1_Iter1 << " ";
cout << ")." << endl;
// Remove consecutive duplicates under the binary prediate mod_equals
v1_NewEnd2 = unique ( v1.begin ( ) , v1_NewEnd1 , mod_equal );
cout << "Removing adjacent duplicates from vector v1 under the\n "
<< " binary predicate mod_equal gives\n ( " ;
for ( v1_Iter2 = v1.begin( ) ; v1_Iter2 != v1_NewEnd2 ; v1_Iter2++ )
cout << *v1_Iter2 << " ";
cout << ")." << endl;
// Remove elements if preceded by an element that was greater
v1_NewEnd3 = unique ( v1.begin ( ) , v1_NewEnd2, greater<int>( ) );
cout << "Removing adjacent elements satisfying the binary\n "
<< " predicate mod_equal from vector v1 gives ( " ;
for ( v1_Iter3 = v1.begin( ) ; v1_Iter3 != v1_NewEnd3 ; v1_Iter3++ )
cout << *v1_Iter3 << " ";
cout << ")." << endl;
return 0;
}
Output:
Vector v1 is ( 5 -5 5 -5 5 -5 5 -5 4 4 4 4 7 ).
Removing adjacent duplicates from vector v1 gives
( 5 -5 5 -5 5 -5 5 -5 4 7 ).
Removing adjacent duplicates from vector v1 under the
binary predicate mod_equal gives
( 5 4 7 ).
Removing adjacent elements satisfying the binary
predicate mod_equal from vector v1 gives ( 5 7 ).