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 }