STL Algorithm std::unique Tutorial

In this example we will discuss std::unique STL Algorithm.

std::unique is a n STL Algorithms that provide a functionality to remove all consecutive duplicate elements from a given range.

For example, we have an array of elements i.e.

1,2,3,3,3,4,4,5,5

As we can see above there are 4 consecutive duplicate element in above list i.e. two 3’s , one 4 and one 5.

Using std::unique algorithm we can remove these consecutive duplicate element from a given range.

std::unique (<START OF RANGE> , <END OF RANGE>);

But an important point to remember is,

std::unique will not decrease the actual size of given range i.e. it will only overwrite the duplicate elements and returns the new virtual end of range.
For example, after running std::unique on above range actual range will become,

1,2,3,4,5,4,4,5,5

As we can see that only first five elements of list are unique.

std::unique returns the new virtual end of range after removing the consecutive duplicate elements.

For example in above range std::unique will return 5. Therefore after executing std::unique we should erase the extra elements from range i.e.

Remove elements from position returned by std::unique till end.

IMP POINT:

std::unique always removes the consecutive duplicate elements. Therefore before executing std::unique we should first the sort the given range, to make sure that duplicate elements are at consecutive positions.

Let’s see how to use std::unique,

Erase Duplicate Elements from a Vector using std::unique

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
	std::vector<int> vecOfInts = {5,3,1,6,7,6,7,6,9,0,2,3,5};

	// First Sort the given range to bring duplicate
	// elements at consecutive positions
	std::sort(vecOfInts.begin(), vecOfInts.end());


	std::vector<int>::iterator newEnd;

	// Override duplicate elements
	newEnd = std::unique(vecOfInts.begin(), vecOfInts.end());

	vecOfInts.erase(newEnd, vecOfInts.end());


	std::for_each(vecOfInts.begin(), vecOfInts.end(),
				[](int a) {
					std::cout<<a<< " , ";
				});

	return 0;
}




 

std::unique uses the == operator to compare the elements in given range. So to remove duplicate elements from vector of class objects we should override == operator in that class.

Using std::unique with vector of use define objects

Suppose we have a class Person with name and id as member variables. Now we want to remove duplicate elements from a vector of class Person objects on the basis of id.

[showads ad=inside_post]
To that we need to to overload == operator in class Person because std::unique algorithm uses this == operator for comparision. Also, wee need to to overload < operator in class Person because std::sort algorithm uses this < operator for comparision while sorting.

Lets see the code of class Person,

class Person {
public:
  std::string m_name;
  int m_id;
  Person(std::string name, int id) :
    m_name(name), m_id(id) {
  }
  bool operator ==(const Person & obj) {
     if (m_id == obj.m_id)
       return true;
     else
       return false;
  }
bool operator <(const Person & obj) {
     if (m_id < obj.m_id)
        return true;
     else
        return false;
   }
};

 

Now lets use std::unique to remove duplicate elements from vector of class Person objects

int example1() {
	
	std::vector<Person> vecOfPersons = { Person("aaa", 7), Person("kkk", 3),
			Person("aaa", 10), Person("kkk", 7) };

	std::sort(vecOfPersons.begin(), vecOfPersons.end());

	vecOfPersons.erase(std::unique(vecOfPersons.begin(), vecOfPersons.end()) , vecOfPersons.end());

	std::cout << "After removing duplicate Persons List based on ID\n";
	std::for_each(vecOfPersons.begin(), vecOfPersons.end(), [](Person & obj) {
		std::cout<<obj.m_id<< " :: "<<obj.m_name<<std::endl;
	});

}

Output: After removing duplicate Persons List based on ID 3 :: kkk 7 :: aaa 10 :: aaa

Using std::unique with Comparators

Now suppose a new requirement comes and we want to remove duplicates from a vector of class Person objects based on its name instead of id. Also we can not change the current implementation of == operator in class. In such scenario we will use overloaded version of std::unique that accepts a comparator (Function Pointer/ Object) as an argument and uses that for comparisons instead of == operator. Lets see how to define a Function Object for this scenario

struct PersonEqualityCompartor 
{
  bool operator()(const Person & first, const Person & sec) {
     if (first.m_name == sec.m_name)
       return true;
     else
       return false;
    }
};

struct PersonCompartor {
    bool operator()(const Person & first, const Person & sec) {
        if (first.m_name < sec.m_name)
          return true;
        else
          return false;
}
};

Now lets use this comparator in std::unique for removing duplicate Person Objects based on name i.e.

int example2() {
	
	std::vector<Person> vecOfPersons = { Person("aaa", 7), Person("kkk", 3),
			Person("aaa", 10), Person("kkk", 2) };

	std::sort(vecOfPersons.begin(), vecOfPersons.end(), PersonCompartor());

	std::vector<Person>::iterator newEnd;
	newEnd = std::unique(vecOfPersons.begin(), vecOfPersons.end(), PersonEqualityCompartor()); 
	
	vecOfPersons.erase( newEnd, vecOfPersons.end());

	std::cout << "After removing duplicate Persons List based on Name\n";
	std::for_each(vecOfPersons.begin(), vecOfPersons.end(), [](Person & obj) {
		std::cout<<obj.m_id<< " :: "<<obj.m_name<<std::endl;
	});
}

 

Output:

After removing duplicate Persons List based on Name
7 :: aaa
3 :: kkk

We can do the same using lambda function instead of Function Object i.e.

Using std::unique with lambda function

int example3() {
	
	std::vector<Person> vecOfPersons = { Person("aaa", 7), Person("kkk", 3),
			Person("aaa", 10), Person("kkk", 2) };

	std::sort(vecOfPersons.begin(), vecOfPersons.end(), [](const Person & first, const Person & sec) {
		if (first.m_name < sec.m_name)
			return true;
		else
			return false;
	});

	std::vector<Person>::iterator newEnd;
	newEnd = std::unique(vecOfPersons.begin(), vecOfPersons.end(), [](const Person & first, const Person & sec) {
		if (first.m_name == sec.m_name)
			return true;
		else
			return false;
	}); 
	
	vecOfPersons.erase( newEnd, vecOfPersons.end());

	std::cout << "After removing duplicate Persons List based on Name\n";
	std::for_each(vecOfPersons.begin(), vecOfPersons.end(), [](Person & obj) {
		std::cout<<obj.m_id<< " :: "<<obj.m_name<<std::endl;
	});
}

 

Output:

After removing duplicate Persons List based on Name
7 :: aaa
3 :: kkk

To compile above code use c++11 compiler for example on linux use command,
g++ –std=c++11 sample.cpp

Complete code is as follows,

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

class Person {
public:
	std::string m_name;
	int m_id;
	Person(std::string name, int id) :
			m_name(name), m_id(id) {
	}
	bool operator ==(const Person & obj) {
		if (m_id == obj.m_id)
			return true;
		else
			return false;
	}
	bool operator <(const Person & obj) {
		if (m_id < obj.m_id)
			return true;
		else
			return false;
	}
};

struct PersonEqualityCompartor {
	bool operator()(const Person & first, const Person & sec) {
		if (first.m_name == sec.m_name)
			return true;
		else
			return false;
	}
};

struct PersonCompartor {
	bool operator()(const Person & first, const Person & sec) {
		if (first.m_name < sec.m_name)
			return true;
		else
			return false;
	}
};

int example1() {
	
	std::vector<Person> vecOfPersons = { Person("aaa", 7), Person("kkk", 3),
			Person("aaa", 10), Person("kkk", 7) };

	std::sort(vecOfPersons.begin(), vecOfPersons.end());

	vecOfPersons.erase(std::unique(vecOfPersons.begin(), vecOfPersons.end()) , vecOfPersons.end());

	std::cout << "After removing duplicate Persons List based on ID\n";
	std::for_each(vecOfPersons.begin(), vecOfPersons.end(), [](Person & obj) {
		std::cout<<obj.m_id<< " :: "<<obj.m_name<<std::endl;
	});

}

int example2() {
	
	std::vector<Person> vecOfPersons = { Person("aaa", 7), Person("kkk", 3),
			Person("aaa", 10), Person("kkk", 2) };

	std::sort(vecOfPersons.begin(), vecOfPersons.end(), PersonCompartor());

	std::vector<Person>::iterator newEnd;
	newEnd = std::unique(vecOfPersons.begin(), vecOfPersons.end(), PersonEqualityCompartor()); 
	
	vecOfPersons.erase( newEnd, vecOfPersons.end());

	std::cout << "After removing duplicate Persons List based on Name\n";
	std::for_each(vecOfPersons.begin(), vecOfPersons.end(), [](Person & obj) {
		std::cout<<obj.m_id<< " :: "<<obj.m_name<<std::endl;
	});
}
int example3() {
	
	std::vector<Person> vecOfPersons = { Person("aaa", 7), Person("kkk", 3),
			Person("aaa", 10), Person("kkk", 2) };

	std::sort(vecOfPersons.begin(), vecOfPersons.end(), [](const Person & first, const Person & sec) {
		if (first.m_name < sec.m_name)
			return true;
		else
			return false;
	});

	std::vector<Person>::iterator newEnd;
	newEnd = std::unique(vecOfPersons.begin(), vecOfPersons.end(), [](const Person & first, const Person & sec) {
		if (first.m_name == sec.m_name)
			return true;
		else
			return false;
	}); 
	
	vecOfPersons.erase( newEnd, vecOfPersons.end());

	std::cout << "After removing duplicate Persons List based on Name\n";
	std::for_each(vecOfPersons.begin(), vecOfPersons.end(), [](Person & obj) {
		std::cout<<obj.m_id<< " :: "<<obj.m_name<<std::endl;
	});
}
int main()
{
	example1();
	example2();
	example3();
	return 0;
}

 

 

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top