1 /// Random array functions
2 module unexpected.array;
3 
4 import std.range : hasLength, hasLvalueElements, isBidirectionalRange, isRandomAccessRange;
5 
6 auto removeRandom(RNG, Range)(ref RNG rng, ref Range range) @safe pure if (hasLength!Range && isBidirectionalRange!Range && hasLvalueElements!Range) {
7 	import std.algorithm.mutation : remove;
8 	import std.exception : enforce;
9 	import std.random : uniform;
10 	enforce(range.length > 0, "Error: Nothing to remove");
11 	auto idx = uniform(0, range.length, rng);
12 	auto result = range[idx];
13 	range = range.remove(idx);
14 	return result;
15 }
16 
17 @safe unittest {
18 	import std.random : rndGen;
19 	auto array = [1];
20 	assert(removeRandom(rndGen, array) == 1);
21 	assert(array.length == 0);
22 }
23 
24 auto randomMatchedWithoutRepeats(RNG, T)(T arr, ref RNG rng) if (hasLength!T && isRandomAccessRange!T)  {
25 	import std.array : array;
26 	import std.random : randomShuffle;
27 	import std.range : indexed, iota;
28 	auto indexes = iota(0, arr.length).array;
29 	randomShuffle(indexes, rng);
30 	return indexed(arr, indexes);
31 }
32 
33 auto randomMatchedWithRepeats(RNG, T)(T arr, ref RNG rng) if (hasLength!T && isRandomAccessRange!T)  {
34 	import std.random : choice;
35 	import std.range;
36 	struct Result {
37 		typeof(T.init.front) front;
38 		bool empty() const {
39 			return arr.empty;
40 		}
41 		void popFront() {
42 			front = choice(arr, rng);
43 		}
44 	}
45 	Result output;
46 	if (!output.empty) {
47 		output.popFront();
48 	}
49 	return output;
50 }
51 
52 @safe pure unittest {
53 	import std.random : Random;
54 	auto rng = Random.init;
55 	assert((int[]).init.randomMatchedWithRepeats(rng).empty);
56 	assert([1].randomMatchedWithRepeats(rng).front == 1);
57 }