Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
std::ranges::unique(3)	      C++ Standard Libary	std::ranges::unique(3)

NAME
       std::ranges::unique - std::ranges::unique

Synopsis
	  Defined in header <algorithm>
	  Call signature
	  template< std::permutable I, std::sentinel_for<I> S, class Proj =
	  std::identity,

		    std::indirect_equivalence_relation<std::projected<I,
       Proj>>	  (1) (since
			C	     =		  ranges::equal_to	     >
       C++20)
	  constexpr ranges::subrange<I>

	      unique( I	first, S last, C comp =	{}, Proj proj =	{} );
	  template< ranges::forward_range R, class Proj	= std::identity,

	  std::indirect_equivalence_relation<std::projected<ranges::itera-
       tor_t<R>,
	  Proj>>
       (2) (since
			C	    =		 ranges::equal_to	     >
       C++20)
	  requires std::permutable<ranges::iterator_t<R>>
	  constexpr ranges::borrowed_subrange_t<R>

	      unique( R&& r, C comp = {}, Proj proj = {} );

	  1)  Eliminates  all  except the first	element	from every consecutive
       group of
	  equivalent elements from the range [first, last) and returns a  sub-
       range [ret, last),
	  where	ret is a past-the-end iterator for the new end of the range.
	  Two  consecutive  elements *(i - 1) and *i are considered equivalent
       if
	  std::invoke(comp, std::invoke(proj,  *(i  -  1)),  std::invoke(proj,
       *i)) == true, where
	  i is an iterator in the range	[first + 1, last).
	  2)  Same  as	(1),  but uses r as the	range, as if using ranges::be-
       gin(r) as first,	and
	  ranges::end(r) as last.

	  The function-like entities described on  this	 page  are  niebloids,
       that is:

	    *  Explicit	template argument lists	cannot be specified when call-
       ing any of them.
	    * None of them are visible to argument-dependent lookup.
	    * When any of them are found by normal unqualified lookup  as  the
       name to the left
	      of  the function-call operator, argument-dependent lookup	is in-
       hibited.

	  In practice, they may	be implemented as function  objects,  or  with
       special compiler
	  extensions.

Parameters
	  first, last -	the range of elements to process
	  r	      -	the range of elements to process
	  comp	      -	the binary predicate to	compare	the projected elements
	  proj	      -	the projection to apply	to the elements

Return value
	  Returns  {ret,  last},  where	ret is a past-the-end iterator for the
       new end of the
	  range.

Complexity
	  For nonempty ranges, exactly ranges::distance(first, last) -	1  ap-
       plications of the
	  corresponding	predicate comp and no more that	twice as many applica-
       tions of	any
	  projection proj.

Notes
	  Removing  is done by shifting	(by means of move assignment) the ele-
       ments in	the range
	  in such a way	that the elements that are not to be removed appear in
       the beginning
	  of the range.	Relative order of the elements	that  remain  is  pre-
       served and the
	  physical  size  of  the  container  is unchanged. Iterators in [ret,
       last) (if any) are
	  still	dereferenceable, but the elements themselves have  unspecified
       values (as per
	  MoveAssignable post-condition).

	  A  call  to ranges::unique is	sometimes followed by a	call to	a con-
       tainers erase
	  member function, which erases	the unspecified	values and reduces the
       physical	size
	  of the container to match its	new logical size.  These  two  invoca-
       tions together model
	  the Eraseremove idiom.

Possible implementation
       struct unique_fn	{
	   template<std::permutable  I,	 std::sentinel_for<I>  S, class	Proj =
       std::identity,
		    std::indirect_equivalence_relation<std::projected<I,
       Proj>>
			C = ranges::equal_to>
	   constexpr ranges::subrange<I>
	       operator()(I first, S last, C comp = {},	Proj proj = {})	const
	   {
	       first = ranges::adjacent_find(first, last, comp,	proj);
	       if (first == last)
		   return {first, first};
	       auto i {first};
	       ++first;
	       while (++first != last)
		   if  (!std::invoke(comp,  std::invoke(proj,  *i),   std::in-
       voke(proj, *first)))
		       *++i = ranges::iter_move(first);
	       return {++i, first};
	   }

	   template<ranges::forward_range R, class Proj	= std::identity,
		    std::indirect_equivalence_relation<std::pro-
       jected<ranges::iterator_t<R>, Proj>>
			C = ranges::equal_to>
	   requires std::permutable<ranges::iterator_t<R>>
	   constexpr ranges::borrowed_subrange_t<R>
	       operator()(R&& r, C comp	= {}, Proj proj	= {}) const
	   {
	       return (*this)(ranges::begin(r),	ranges::end(r),
			      std::move(comp), std::move(proj));
	   } };

       inline constexpr	unique_fn unique {};

Example
       // Run this code

	#include <algorithm>
	#include <cmath>
	#include <complex>
	#include <iostream>
	#include <vector>

	struct id {
	    int	i;
	    explicit id(int i) : i {i} {}
	};

	void print(id i, const auto& v)
	{
	    std::cout << i.i <<	") ";
	    std::ranges::for_each(v,  [](auto  const& e) { std::cout <<	e << '
       '; });
	    std::cout << '\n';
	}

	int main()
	{
	    // a vector	containing several duplicated elements
	    std::vector<int> v {1, 2, 1, 1, 3, 3, 3, 4,	5, 4};

	    print(id {1}, v);

	    // remove consecutive (adjacent) duplicates
	    const auto ret = std::ranges::unique(v);
	    // v now holds {1 2	1 3 4 5	4 x x x}, where	'x' is indeterminate
	    v.erase(ret.begin(), ret.end());
	    print(id {2}, v);

	    // sort followed by	unique,	to remove all duplicates
	    std::ranges::sort(v); // {1	1 2 3 4	4 5}
	    print(id {3}, v);

	    const  auto	  [first,   last]   =	std::ranges::unique(v.begin(),
       v.end());
	    // v now holds {1 2	3 4 5 x	x}, where 'x' is indeterminate
	    v.erase(first, last);
	    print(id {4}, v);

	    // unique with custom comparison and projection
	    std::vector<std::complex<int>>  vc { {1, 1}, {-1, 2}, {-2, 3}, {2,
       4}, {-3,	5} };
	    print(id {5}, vc);

	    const auto ret2 = std::ranges::unique(vc,
		// consider two	complex	nums equal if  their  real  parts  are
       equal by	module:
		[](int	x,  int	 y) { return std::abs(x) == std::abs(y); }, //
       comp
		[](std::complex<int> z)	{ return  z.real();  }		    //
       proj
	    );
	    vc.erase(ret2.begin(), ret2.end());
	    print(id {6}, vc);
	}

Output:
	1) 1 2 1 1 3 3 3 4 5 4
	2) 1 2 1 3 4 5 4
	3) 1 1 2 3 4 4 5
	4) 1 2 3 4 5
	5) (1,1) (-1,2)	(-2,3) (2,4) (-3,5)
	6) (1,1) (-2,3)	(-3,5)

See also
	  ranges::unique_copy	 creates a copy	of some	range of elements that
       contains	no
	  (C++20)		consecutive duplicates
				(niebloid)
	  ranges::adjacent_find	finds the first	two adjacent  items  that  are
       equal (or satisfy
	  (C++20)		a given	predicate)
				(niebloid)
	  ranges::remove
	  ranges::remove_if	removes	elements satisfying specific criteria
	  (C++20)		(niebloid)
	  (C++20)
	  unique		 removes  consecutive  duplicate elements in a
       range
				(function template)
	  unique		removes	consecutive duplicate elements
				(public	member function	of std::list<T,Alloca-
       tor>)
				removes	consecutive duplicate elements
	  unique		  (public   member   function	of   std::for-
       ward_list<T,Allocator>)

http://cppreference.com		  2024.06.10		std::ranges::unique(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=std::ranges::unique&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help