Faker C++
Loading...
Searching...
No Matches
helper.h
Go to the documentation of this file.
1#pragma once
2
3#include <numeric>
4#include <random>
5#include <vector>
6
7#include "generator.h"
8#include "number.h"
9
11{
12template <typename T>
14 std::ranges::input_range<T> && (std::ranges::sized_range<T> || std::ranges::forward_range<T>);
15
16template <input_range_with_faster_size_compute_than_linear_rng Range>
17decltype(auto) randomElement(Range&& range)
18{
19 if (std::ranges::empty(range))
20 {
21 throw std::invalid_argument{"Range [start, end) is empty."};
22 }
23
24 const auto size = std::ranges::distance(range);
25
26 const auto index = number::integer(size - 1);
27
28 return (*std::ranges::next(range.begin(), index));
29}
30
31template <std::ranges::input_range Range>
32auto randomElement(Range&& range)
33{
34 auto const end = range.end();
35 auto itr = range.begin();
36
37 if (itr == end)
38 {
39 throw std::invalid_argument{"Range [start, end) is empty."};
40 }
41
42 std::mt19937_64& gen = getGenerator();
43
44 using RangeValue = std::ranges::range_value_t<decltype(range)>;
45 auto consume_itr = [&itr]() -> decltype(auto)
46 {
47 using reference_type = std::ranges::range_reference_t<decltype(range)>;
48 if constexpr (std::is_reference_v<reference_type>)
49 {
50 return std::move(*itr);
51 }
52 else
53 {
54 return *itr;
55 }
56 };
57
58 RangeValue result = consume_itr();
59
60 ++itr;
61
62 std::size_t count = 1;
63
64 for (; itr != end; ++itr, ++count)
65 {
66 std::uniform_int_distribution<size_t> distrib(0, count);
67 if (distrib(gen) == 0)
68 {
69 result = consume_itr();
70 }
71 }
72
73 return result;
74}
75
90
91template <class T>
93{
94 unsigned weight;
96};
97
98template <class T>
99T weightedRandomElement(const std::vector<WeightedElement<T>>& data)
100{
101 if (data.empty())
102 {
103 throw std::invalid_argument{"Data is empty."};
104 }
105
106 const auto sumOfWeights =
107 std::accumulate(data.begin(), data.end(), 0u,
108 [](unsigned sum, const WeightedElement<T>& element) { return sum + element.weight; });
109
110 if (sumOfWeights == 0u)
111 {
112 throw std::invalid_argument{"Sum of weights cannot be zero."};
113 }
114
115 const auto targetWeightValue = number::integer(1u, sumOfWeights);
116
117 auto currentSum = 0u;
118
119 for (const auto& elem : data)
120 {
121 currentSum += elem.weight;
122
123 if (currentSum > targetWeightValue)
124 {
125 return elem.value;
126 }
127 }
128
129 return data.back().value;
130}
131
132}
Definition helper.h:11
T weightedRandomElement(const std::vector< WeightedElement< T > > &data)
Definition helper.h:99
decltype(auto) randomElement(Range &&range)
Definition helper.h:17
I integer(I min, I max)
Generates a random integer number in the given range, bounds included.
Definition number.h:31
FAKER_CXX_EXPORT std::mt19937_64 & getGenerator()
Get a random element by weight from a vector.
Definition helper.h:93
unsigned weight
Definition helper.h:94
T value
Definition helper.h:95