Skip to content

Commit 087ffa2

Browse files
authored
Added support for empty case in random collections (#18568)
1 parent 195e723 commit 087ffa2

File tree

14 files changed

+361
-219
lines changed

14 files changed

+361
-219
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
### Fixed
2+
3+
### Added
4+
5+
### Changed
6+
7+
* Random functions support for zero element chosen/sampled ([PR #18568](https://github.com/dotnet/fsharp/pull/18568))
8+
9+
### Breaking Changes

src/FSharp.Core/array.fs

Lines changed: 71 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,15 +2020,18 @@ module Array =
20202020
let inputLength = source.Length
20212021

20222022
if inputLength = 0 then
2023-
invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
2024-
2025-
let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
2023+
if count = 0 then
2024+
[||]
2025+
else
2026+
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
2027+
else
2028+
let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
20262029

2027-
for i = 0 to count - 1 do
2028-
let j = random.Next(0, inputLength)
2029-
result[i] <- source[j]
2030+
for i = 0 to count - 1 do
2031+
let j = random.Next(0, inputLength)
2032+
result[i] <- source[j]
20302033

2031-
result
2034+
result
20322035

20332036
[<CompiledName("RandomChoicesBy")>]
20342037
let randomChoicesBy (randomizer: unit -> float) (count: int) (source: 'T array) : 'T array =
@@ -2040,15 +2043,18 @@ module Array =
20402043
let inputLength = source.Length
20412044

20422045
if inputLength = 0 then
2043-
invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
2044-
2045-
let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
2046+
if count = 0 then
2047+
[||]
2048+
else
2049+
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
2050+
else
2051+
let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
20462052

2047-
for i = 0 to count - 1 do
2048-
let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
2049-
result[i] <- source[j]
2053+
for i = 0 to count - 1 do
2054+
let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
2055+
result[i] <- source[j]
20502056

2051-
result
2057+
result
20522058

20532059
[<CompiledName("RandomChoices")>]
20542060
let randomChoices (count: int) (source: 'T array) : 'T array =
@@ -2065,35 +2071,38 @@ module Array =
20652071
let inputLength = source.Length
20662072

20672073
if inputLength = 0 then
2068-
invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
2069-
2070-
if count > inputLength then
2071-
invalidArg "count" (SR.GetString(SR.notEnoughElements))
2074+
if count = 0 then
2075+
[||]
2076+
else
2077+
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
2078+
else
2079+
if count > inputLength then
2080+
invalidArg "count" (SR.GetString(SR.notEnoughElements))
20722081

2073-
let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
2082+
let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
20742083

2075-
let setSize =
2076-
Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
2084+
let setSize =
2085+
Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
20772086

2078-
if inputLength <= setSize then
2079-
let pool = copy source
2087+
if inputLength <= setSize then
2088+
let pool = copy source
20802089

2081-
for i = 0 to count - 1 do
2082-
let j = random.Next(0, inputLength - i)
2083-
result[i] <- pool[j]
2084-
pool[j] <- pool[inputLength - i - 1]
2085-
else
2086-
let selected = HashSet()
2090+
for i = 0 to count - 1 do
2091+
let j = random.Next(0, inputLength - i)
2092+
result[i] <- pool[j]
2093+
pool[j] <- pool[inputLength - i - 1]
2094+
else
2095+
let selected = HashSet()
20872096

2088-
for i = 0 to count - 1 do
2089-
let mutable j = random.Next(0, inputLength)
2097+
for i = 0 to count - 1 do
2098+
let mutable j = random.Next(0, inputLength)
20902099

2091-
while not (selected.Add j) do
2092-
j <- random.Next(0, inputLength)
2100+
while not (selected.Add j) do
2101+
j <- random.Next(0, inputLength)
20932102

2094-
result[i] <- source[j]
2103+
result[i] <- source[j]
20952104

2096-
result
2105+
result
20972106

20982107
[<CompiledName("RandomSampleBy")>]
20992108
let randomSampleBy (randomizer: unit -> float) (count: int) (source: 'T array) : 'T array =
@@ -2105,39 +2114,42 @@ module Array =
21052114
let inputLength = source.Length
21062115

21072116
if inputLength = 0 then
2108-
invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
2109-
2110-
if count > inputLength then
2111-
invalidArg "count" (SR.GetString(SR.notEnoughElements))
2117+
if count = 0 then
2118+
[||]
2119+
else
2120+
invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
2121+
else
2122+
if count > inputLength then
2123+
invalidArg "count" (SR.GetString(SR.notEnoughElements))
21122124

2113-
let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
2125+
let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count
21142126

2115-
// algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456
2116-
let setSize =
2117-
Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
2127+
// algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456
2128+
let setSize =
2129+
Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count
21182130

2119-
if inputLength <= setSize then
2120-
let pool = copy source
2131+
if inputLength <= setSize then
2132+
let pool = copy source
21212133

2122-
for i = 0 to count - 1 do
2123-
let j =
2124-
Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i)
2134+
for i = 0 to count - 1 do
2135+
let j =
2136+
Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i)
21252137

2126-
result[i] <- pool[j]
2127-
pool[j] <- pool[inputLength - i - 1]
2128-
else
2129-
let selected = HashSet()
2138+
result[i] <- pool[j]
2139+
pool[j] <- pool[inputLength - i - 1]
2140+
else
2141+
let selected = HashSet()
21302142

2131-
for i = 0 to count - 1 do
2132-
let mutable j =
2133-
Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
2143+
for i = 0 to count - 1 do
2144+
let mutable j =
2145+
Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
21342146

2135-
while not (selected.Add j) do
2136-
j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
2147+
while not (selected.Add j) do
2148+
j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength
21372149

2138-
result[i] <- source[j]
2150+
result[i] <- source[j]
21392151

2140-
result
2152+
result
21412153

21422154
[<CompiledName("RandomSample")>]
21432155
let randomSample (count: int) (source: 'T array) : 'T array =

src/FSharp.Core/array.fsi

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3282,7 +3282,7 @@ module Array =
32823282
/// <returns>An array of randomly selected elements from the input array.</returns>
32833283
///
32843284
/// <exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
3285-
/// <exception cref="T:System.ArgumentException">Thrown when the input array is empty.</exception>
3285+
/// <exception cref="T:System.ArgumentException">Thrown when count is more than 0 and the input array is empty.</exception>
32863286
/// <exception cref="T:System.ArgumentException">Thrown when count is less than 0.</exception>
32873287
///
32883288
/// <example id="randomChoices-1">
@@ -3306,7 +3306,7 @@ module Array =
33063306
///
33073307
/// <exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
33083308
/// <exception cref="T:System.ArgumentNullException">Thrown when the random argument is null.</exception>
3309-
/// <exception cref="T:System.ArgumentException">Thrown when the input array is empty.</exception>
3309+
/// <exception cref="T:System.ArgumentException">Thrown when count is more than 0 and the input array is empty.</exception>
33103310
/// <exception cref="T:System.ArgumentException">Thrown when count is less than 0.</exception>
33113311
///
33123312
/// <example id="randomChoicesWith-1">
@@ -3329,7 +3329,7 @@ module Array =
33293329
/// <returns>An array of randomly selected elements from the input array.</returns>
33303330
///
33313331
/// <exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
3332-
/// <exception cref="T:System.ArgumentException">Thrown when the input array is empty.</exception>
3332+
/// <exception cref="T:System.ArgumentException">Thrown when count is more than 0 and the input array is empty.</exception>
33333333
/// <exception cref="T:System.ArgumentException">Thrown when count is less than 0.</exception>
33343334
/// <exception cref="T:System.ArgumentOutOfRangeException">Thrown when the randomizer function returns a value outside the range [0, 1).</exception>
33353335
///
@@ -3352,7 +3352,7 @@ module Array =
33523352
/// <returns>An array of randomly selected elements from the input array.</returns>
33533353
///
33543354
/// <exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
3355-
/// <exception cref="T:System.ArgumentException">Thrown when the input array is empty.</exception>
3355+
/// <exception cref="T:System.ArgumentException">Thrown when count is more than 0 and the input array is empty.</exception>
33563356
/// <exception cref="T:System.ArgumentException">Thrown when count is less than 0.</exception>
33573357
/// <exception cref="T:System.ArgumentException">Thrown when count is greater than the length of the input array.</exception>
33583358
///
@@ -3377,7 +3377,7 @@ module Array =
33773377
///
33783378
/// <exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
33793379
/// <exception cref="T:System.ArgumentNullException">Thrown when the random argument is null.</exception>
3380-
/// <exception cref="T:System.ArgumentException">Thrown when the input array is empty.</exception>
3380+
/// <exception cref="T:System.ArgumentException">Thrown when count is more than 0 and the input array is empty..</exception>
33813381
/// <exception cref="T:System.ArgumentException">Thrown when count is less than 0.</exception>
33823382
/// <exception cref="T:System.ArgumentException">Thrown when count is greater than the length of the input array.</exception>
33833383
///
@@ -3401,7 +3401,7 @@ module Array =
34013401
/// <returns>An array of randomly selected elements from the input array.</returns>
34023402
///
34033403
/// <exception cref="T:System.ArgumentNullException">Thrown when the input array is null.</exception>
3404-
/// <exception cref="T:System.ArgumentException">Thrown when the input array is empty.</exception>
3404+
/// <exception cref="T:System.ArgumentException">Thrown when count is more than 0 and the input array is empty.</exception>
34053405
/// <exception cref="T:System.ArgumentException">Thrown when count is less than 0.</exception>
34063406
/// <exception cref="T:System.ArgumentException">Thrown when count is greater than the length of the input array.</exception>
34073407
/// <exception cref="T:System.ArgumentOutOfRangeException">Thrown when the randomizer function returns a value outside the range [0, 1).</exception>

0 commit comments

Comments
 (0)