File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 11using System ;
2+ using System . Collections . Generic ;
23
34namespace RandomGen . Fluent
45{
56 public interface INumbers : IFluentInterface
67 {
78 Func < byte > Bytes ( byte min = byte . MinValue , byte max = byte . MaxValue ) ;
89 Func < int > Integers ( int min = 0 , int max = 100 ) ;
10+ Func < IEnumerable < int > > IntegersDrawNoPlacement ( int min = 0 , int max = 100 , int take = 1 ) ;
911 Func < uint > UnsignedIntegers ( uint min = 0 , uint max = 100 ) ;
1012 Func < long > Longs ( long min = 0 , long max = 100 ) ;
1113 IDouble Doubles ( ) ;
Original file line number Diff line number Diff line change @@ -74,6 +74,14 @@ public interface IRandom : IFluentInterface
7474 /// <param name="weights">Optional weights affecting the likelihood of a value being chosen. Same length as Enum values</param>
7575 Func < T > Enum < T > ( IEnumerable < double > weights = null ) where T : struct , IConvertible ;
7676
77+ /// <summary>
78+ /// Returns a list of randomly drawn elements without placements
79+ /// </summary>
80+ /// <typeparam name="T"></typeparam>
81+ /// <param name="items"></param>
82+ /// <param name="take">The numbers of desired drawn elements</param>
83+ Func < IEnumerable < T > > ItemsNoPlacement < T > ( IEnumerable < T > items , int take = 1 ) ;
84+
7785 /// <summary>
7886 /// Generates random country names
7987 /// Based on System.Globalisation
Original file line number Diff line number Diff line change @@ -35,6 +35,32 @@ public Func<int> Integers(int min = 0, int max = 100)
3535 return ( ) => random . Next ( min , max ) ;
3636 }
3737
38+ public Func < IEnumerable < int > > IntegersDrawNoPlacement ( int min = 0 , int max = 100 , int take = 1 )
39+ {
40+ if ( min >= max )
41+ throw new ArgumentOutOfRangeException ( "min >= max" ) ;
42+ if ( take > ( max - min ) )
43+ throw new ArgumentOutOfRangeException ( "available < take" ) ;
44+
45+ var pool = Enumerable . Range ( 0 , max - min ) . ToArray ( ) ;
46+ var result = new List < int > ( ) ;
47+ var random = this . _genLink . CreateRandom ( ) ;
48+
49+ //Modern Fisher–Yates shuffle with O(n) complexity
50+ for ( int i = 0 ; i < take ; i ++ )
51+ {
52+ var itemIndex = random . Next ( min , max - i ) ;
53+
54+ // swap taken index and current last
55+ var buffer = pool [ itemIndex ] ;
56+ pool [ itemIndex ] = pool [ max - i - 1 ] ;
57+ pool [ max - i - 1 ] = buffer ;
58+ result . Add ( buffer + min ) ;
59+ }
60+
61+ return ( ) => result ;
62+ }
63+
3864 public Func < uint > UnsignedIntegers ( uint min = 0 , uint max = 100 )
3965 {
4066 if ( min >= max )
Original file line number Diff line number Diff line change @@ -99,5 +99,13 @@ public Func<string> Countries()
9999
100100 return this . Items ( data ) ;
101101 }
102+
103+ public Func < IEnumerable < T > > ItemsNoPlacement < T > ( IEnumerable < T > items , int take = 1 )
104+ {
105+ var indexes = this . Numbers . IntegersDrawNoPlacement ( 0 , items . Count ( ) , take ) ( ) ;
106+ var result = indexes . Select ( i => items . ElementAt ( i ) ) ;
107+
108+ return ( ) => result ;
109+ }
102110 }
103111}
Original file line number Diff line number Diff line change 11using System ;
22using System . Collections . Concurrent ;
33using System . Collections . Generic ;
4+ using System . Diagnostics ;
45using System . Linq ;
56using System . Text ;
67using System . Threading ;
@@ -219,6 +220,28 @@ public void RandomItems()
219220 Console . WriteLine ( item ) ;
220221 }
221222 }
223+
224+ [ Fact ]
225+ public void RandomItemsNoPlacement ( )
226+ {
227+ var take = 1000000 ;
228+ var random = new Random ( ) ;
229+ var input = Enumerable . Range ( 0 , 10000000 ) . ToList ( ) ;
230+
231+ var sw = Stopwatch . StartNew ( ) ;
232+ var fisherYatesShuffle = Gen . Random . ItemsNoPlacement ( input , take ) ( ) . ToList ( ) ;
233+ var fisherYatesTime = sw . Elapsed . TotalSeconds ;
234+
235+ sw . Restart ( ) ;
236+ var normal = input . OrderBy ( x => random . NextDouble ( ) ) . Take ( take ) . ToList ( ) ;
237+ var normalTime = sw . Elapsed . TotalSeconds ;
238+
239+ //check for non duplicate items
240+ Assert . False ( fisherYatesShuffle . GroupBy ( x => x ) . Where ( x => x . Count ( ) > 1 ) . Any ( ) ) ;
241+ Assert . False ( normal . GroupBy ( x => x ) . Where ( x => x . Count ( ) > 1 ) . Any ( ) ) ;
242+
243+ Console . WriteLine ( $ "For large lists Fisher Yates shuffle should outperform random shuffling: { fisherYatesTime } <{ normalTime } ") ;
244+ }
222245
223246 [ Fact ]
224247 public void ListLikelihoodWeightsWorks ( )
You can’t perform that action at this time.
0 commit comments