@@ -19,76 +19,169 @@ public static Random Random
1919 return R . Value ;
2020 }
2121 }
22- public static T RandomSelectOne < T > ( this IList < T > source )
23- {
24- return source [ R . Value . Next ( source . Count ) ] ;
25- }
26- public static T RandomPluck < T > ( this IList < T > source )
22+
23+
24+ public static bool TryRandomPluck < T > ( this LinkedList < T > source , out T value )
2725 {
28- var e = source [ R . Value . Next ( source . Count ) ] ;
29- source . Remove ( e ) ;
30- return e ;
26+ if ( source . Count == 0 )
27+ {
28+ value = default ( T ) ;
29+ return false ;
30+ }
31+
32+ var r = R . Value . Next ( source . Count ) ;
33+ var node = source . First ;
34+ for ( var i = 0 ; i <= r ; i ++ )
35+ node = node . Next ;
36+ value = node . Value ;
37+ source . Remove ( node ) ;
38+ return true ;
3139 }
3240
33- public static T RandomSelectOne < T > ( this T [ ] source )
41+ public static T RandomPluck < T > ( this LinkedList < T > source )
3442 {
35- return source [ R . Value . Next ( source . Length ) ] ;
43+ if ( source . TryRandomPluck ( out T value ) )
44+ return value ;
45+
46+ throw new InvalidOperationException ( "Source collection is empty." ) ;
3647 }
37- public static T RandomSelectOne < T > ( this ICollection < T > source )
48+
49+ public static bool TryRandomPluck < T > ( this IList < T > source , out T value )
3850 {
39- return source . Skip ( R . Value . Next ( source . Count ) ) . First ( ) ;
51+ if ( source . Count == 0 )
52+ {
53+ value = default ( T ) ;
54+ return false ;
55+ }
56+
57+ var r = R . Value . Next ( source . Count ) ;
58+ value = source [ r ] ;
59+ source . RemoveAt ( r ) ;
60+ return true ;
4061 }
41- public static T RandomSelectOne < T > ( this IEnumerable < T > source )
62+
63+ public static T RandomPluck < T > ( this IList < T > source )
4264 {
43- return source . Skip ( R . Value . Next ( source . Count ( ) ) ) . First ( ) ;
65+ if ( source . TryRandomPluck ( out T value ) )
66+ return value ;
67+
68+ throw new InvalidOperationException ( "Source collection is empty." ) ;
4469 }
4570
46- public static int NextRandomIntegerExcluding (
47- int range ,
48- HashSet < int > excludeSet )
71+ public static bool TryRandomSelectOne < T > (
72+ this IReadOnlyList < T > source ,
73+ out T value ,
74+ ISet < T > excluding = null )
4975 {
50- if ( range < 0 )
51- throw new ArgumentOutOfRangeException ( "range" , range , "Must be a number greater than zero." ) ;
52- var r = new List < int > ( ) ;
76+ var count = source . Count ;
77+ if ( count == 0 )
78+ {
79+ value = default ( T ) ;
80+ return false ;
81+ }
5382
54- for ( var i = 0 ; i < range ; ++ i )
83+ if ( excluding == null || excluding . Count == 0 )
5584 {
56- if ( ! excludeSet . Contains ( i ) ) r . Add ( i ) ;
85+ value = source [ R . Value . Next ( count ) ] ;
86+ return true ;
5787 }
5888
59- return r . RandomSelectOne ( ) ;
89+ return source
90+ . Where ( o => ! excluding . Contains ( o ) )
91+ . ToArray ( )
92+ . TryRandomSelectOne ( out value ) ;
6093 }
6194
62- public static uint NextRandomIntegerExcluding (
63- uint range ,
64- HashSet < uint > excludeSet )
95+ public static T RandomSelectOne < T > (
96+ this IReadOnlyList < T > source ,
97+ ISet < T > excluding = null )
6598 {
66- var r = new List < uint > ( ) ;
99+ if ( source . Count == 0 )
100+ throw new InvalidOperationException ( "Source collection is empty." ) ;
67101
68- for ( uint i = 0 ; i < range ; ++ i )
102+ if ( source . TryRandomSelectOne ( out T value , excluding ) )
103+ return value ;
104+
105+ throw new InvalidOperationException ( "Exclusion set invalidates the source. No possible value can be selected." ) ;
106+ }
107+
108+ public static bool TryRandomSelectOneExcept < T > (
109+ this IReadOnlyList < T > source ,
110+ T excluding ,
111+ out T value )
112+ {
113+ var count = source . Count ;
114+ if ( count == 0 )
69115 {
70- if ( ! excludeSet . Contains ( i ) ) r . Add ( i ) ;
116+ value = default ( T ) ;
117+ return false ;
71118 }
72119
73- return r . RandomSelectOne ( ) ;
120+ return source
121+ . Where ( o => ! excluding . Equals ( o ) )
122+ . ToArray ( )
123+ . TryRandomSelectOne ( out value ) ;
124+ }
125+
126+ public static T RandomSelectOneExcept < T > (
127+ this IReadOnlyList < T > source ,
128+ T excluding )
129+ {
130+ if ( source . Count == 0 )
131+ throw new InvalidOperationException ( "Source collection is empty." ) ;
132+
133+ if ( source . TryRandomSelectOneExcept ( excluding , out T value ) )
134+ return value ;
135+
136+ throw new InvalidOperationException ( "Exclusion set invalidates the source. No possible value can be selected." ) ;
74137 }
75138
76- public static uint NextRandomIntegerExcluding (
139+ public static ushort NextRandomIntegerExcluding (
140+ ushort range ,
141+ ISet < ushort > excludeSet )
142+ {
143+ if ( range == 0 )
144+ throw new ArgumentOutOfRangeException ( "range" , range , "Must be a number greater than zero." ) ;
145+
146+ if ( excludeSet == null || excludeSet . Count == 0 )
147+ return ( ushort ) R . Value . Next ( range ) ;
148+
149+ if ( excludeSet . Count == 1 )
150+ return ( ushort ) NextRandomIntegerExcluding ( range , excludeSet . Single ( ) ) ;
151+
152+ return UEnumerable
153+ . Range ( range )
154+ . Where ( i => ! excludeSet . Contains ( i ) )
155+ . ToArray ( )
156+ . RandomSelectOne ( ) ;
157+ }
158+
159+ public static int NextRandomIntegerExcluding (
77160 int range ,
78- HashSet < uint > excludeSet )
161+ ISet < int > excludeSet )
79162 {
80- if ( range < 0 )
163+ if ( range <= 0 )
81164 throw new ArgumentOutOfRangeException ( "range" , range , "Must be a number greater than zero." ) ;
82- var r = new List < uint > ( ) ;
83165
84- for ( uint i = 0 ; i < range ; ++ i )
85- {
86- if ( ! excludeSet . Contains ( i ) ) r . Add ( i ) ;
87- }
166+ if ( excludeSet == null || excludeSet . Count == 0 )
167+ return R . Value . Next ( range ) ;
88168
89- return r . RandomSelectOne ( ) ;
169+ if ( excludeSet . Count == 1 )
170+ return NextRandomIntegerExcluding ( range , excludeSet . Single ( ) ) ;
171+
172+ return Enumerable
173+ . Range ( 0 , range )
174+ . Where ( i => ! excludeSet . Contains ( i ) )
175+ . ToArray ( )
176+ . RandomSelectOne ( ) ;
90177 }
91178
179+ public static ushort NextRandomIntegerExcluding (
180+ ushort range ,
181+ IEnumerable < ushort > excluding )
182+ {
183+ return NextRandomIntegerExcluding ( range , new HashSet < ushort > ( excluding ) ) ;
184+ }
92185
93186 public static int NextRandomIntegerExcluding (
94187 int range ,
@@ -101,50 +194,37 @@ public static int NextRandomIntegerExcluding(
101194 int range ,
102195 int excluding )
103196 {
104- if ( range < 0 )
197+ if ( range <= 0 )
105198 throw new ArgumentOutOfRangeException ( "range" , range , "Must be a number greater than zero." ) ;
106- var r = new List < int > ( ) ;
107199
108- for ( var i = 0 ; i < range ; ++ i )
200+ if ( excluding == 0 )
109201 {
110- if ( excluding != i ) r . Add ( i ) ;
202+ if ( range == 1 )
203+ throw new ArgumentException ( "No value is available with a range of 1 and exclusion of 0." , "range" ) ;
204+ return R . Value . Next ( range - 1 ) + 1 ;
111205 }
112206
113- return r . RandomSelectOne ( ) ;
114- }
207+ if ( excluding >= range || excluding < 0 )
208+ return R . Value . Next ( range ) ;
115209
116- public static uint NextRandomIntegerExcluding (
117- int range ,
118- uint excluding )
119- {
120- if ( range < 0 )
121- throw new ArgumentOutOfRangeException ( "range" , range , "Must be a number greater than zero." ) ;
122- var r = new List < uint > ( ) ;
210+ if ( excluding == range - 1 )
211+ return R . Value . Next ( range - 1 ) ;
123212
124- for ( uint i = 0 ; i < range ; ++ i )
125- {
126- if ( excluding != i ) r . Add ( i ) ;
127- }
128-
129- return r . RandomSelectOne ( ) ;
213+ return Enumerable
214+ . Range ( 0 , range )
215+ . Where ( i => i != excluding )
216+ . ToArray ( )
217+ . RandomSelectOne ( ) ;
130218 }
131219
132- public static uint NextRandomIntegerExcluding (
133- uint range ,
220+ public static int NextRandomIntegerExcluding (
221+ int range ,
134222 uint excluding )
135223 {
136- var r = new List < uint > ( ) ;
137-
138- for ( uint i = 0 ; i < range ; ++ i )
139- {
140- if ( excluding != i ) r . Add ( i ) ;
141- }
142-
143- return r . RandomSelectOne ( ) ;
224+ return NextRandomIntegerExcluding ( range ,
225+ excluding > int . MaxValue ? - 1 : ( int ) excluding ) ;
144226 }
145227
146228 }
147229
148-
149-
150230}
0 commit comments