Namespaces
Variants
Actions

std::ranges::sample

From cppreference.com
< cpp‎ | algorithm‎ | ranges
 
 
Algorithm library
Constrained algorithms and algorithms on ranges(C++20)
Constrained algorithms, e.g. ranges::copy, ranges::sort, ...
Execution policies (C++17)
Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
(C++11)
(C++17)
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
 
Constrained algorithms
All names in this menu belong to namespace std::ranges
Non-modifying sequence operations
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations (on sorted ranges)
       
       
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Permutation operations
Fold operations
Operations on uninitialized storage
Return types
 
Defined in header <algorithm>
Call signature
template<std::input_iterator I, std::sentinel_for<I> S,

          std::weakly_incrementable O, class Gen >
requires (std::forward_iterator<I>||std::random_access_iterator<O>)&&
          std::indirectly_copyable<I, O>&&
          std::uniform_random_bit_generator<std::remove_reference_t<Gen>>

O sample( I first, S last, O out, std::iter_difference_t<I> n, Gen&& gen );
(1) (since C++20)
(2) (since C++20)
1) Selects M = min(n, last - first) elements from the sequence [firstlast) (without replacement) such that each possible sample has equal probability of appearance, and writes those selected elements into the range beginning at out.
The algorithm is stable (preserves the relative order of the selected elements) only if I models std::forward_iterator.
The behavior is undefined if out is in [firstlast).
2) Same as (1), but uses r as the source range, as if using ranges::begin(r) as first, and ranges::end(r) as last.

The function-like entities described on this page are algorithm function objects (informally known as niebloids), that is:

Contents

[edit]Parameters

first, last - the iterator-sentinel pair defining the range of elements from which to make the sampling (the population)
r - the range from which to make the sampling (the population)
out - the output iterator where the samples are written
n - number of samples to take
gen - the random number generator used as the source of randomness

[edit]Return value

An iterator equal to out + M, that is the end of the resulting sample range.

[edit]Complexity

Linear: 𝓞(last - first).

[edit]Notes

This function may implement selection sampling or reservoir sampling.

[edit]Possible implementation

struct sample_fn {template<std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O, class Gen> requires (std::forward_iterator<I> or std::random_access_iterator<O>)&&std::indirectly_copyable<I, O>&&std::uniform_random_bit_generator<std::remove_reference_t<Gen>> O operator()(I first, S last, O out, std::iter_difference_t<I> n, Gen&& gen)const{using diff_t =std::iter_difference_t<I>;using distrib_t =std::uniform_int_distribution<diff_t>;using param_t =typename distrib_t::param_type; distrib_t D{};   ifconstexpr(std::forward_iterator<I>){// this branch preserves "stability" of the sample elementsauto rest{ranges::distance(first, last)};for(n =ranges::min(n, rest); n !=0;++first)if(D(gen, param_t(0, --rest))< n){*out++=*first;--n;}return out;}else{// O is a random_access_iterator diff_t sample_size{};// copy [first, first + M) elements to "random access" outputfor(; first != last && sample_size != n;++first) out[sample_size++]=*first;// overwrite some of the copied elements with randomly selected onesfor(auto pop_size{sample_size}; first != last;++first, ++pop_size){constauto i{D(gen, param_t{0, pop_size})};if(i < n) out[i]=*first;}return out + sample_size;}}   template<ranges::input_range R, std::weakly_incrementable O, class Gen> requires (ranges::forward_range<R> or std::random_access_iterator<O>)&&std::indirectly_copyable<ranges::iterator_t<R>, O>&&std::uniform_random_bit_generator<std::remove_reference_t<Gen>> O operator()(R&& r, O out, ranges::range_difference_t<R> n, Gen&& gen)const{return(*this)(ranges::begin(r), ranges::end(r), std::move(out), n, std::forward<Gen>(gen));}};   inlineconstexpr sample_fn sample {};

[edit]Example

#include <algorithm>#include <iomanip>#include <iostream>#include <iterator>#include <random>#include <vector>   void print(autoconst& rem, autoconst& v){std::cout<< rem <<" = ["<<std::size(v)<<"] { ";for(autoconst& e : v)std::cout<< e <<' ';std::cout<<"}\n";}   int main(){constauto in ={1, 2, 3, 4, 5, 6}; print("in", in);   std::vector<int> out;constint max = in.size()+2;auto gen =std::mt19937{std::random_device{}()};   for(int n{}; n != max;++n){ out.clear(); std::ranges::sample(in, std::back_inserter(out), n, gen);std::cout<<"n = "<< n; print(", out", out);}}

Possible output:

in = [6] { 1 2 3 4 5 6 } n = 0, out = [0] { } n = 1, out = [1] { 5 } n = 2, out = [2] { 4 5 } n = 3, out = [3] { 2 3 5 } n = 4, out = [4] { 2 4 5 6 } n = 5, out = [5] { 1 2 3 5 6 } n = 6, out = [6] { 1 2 3 4 5 6 } n = 7, out = [6] { 1 2 3 4 5 6 }

[edit]See also

randomly re-orders elements in a range
(algorithm function object)[edit]
(C++17)
selects N random elements from a sequence
(function template)[edit]
close