diff --git a/docs/release-notes/.FSharp.Core/8.0.400.md b/docs/release-notes/.FSharp.Core/8.0.400.md index 9c01378c5ef..3f9a780974b 100644 --- a/docs/release-notes/.FSharp.Core/8.0.400.md +++ b/docs/release-notes/.FSharp.Core/8.0.400.md @@ -2,6 +2,8 @@ ### Added +* `Random functions for collections` ([RFC #1135](https://github.com/fsharp/fslang-design/blob/main/RFCs/FS-1135-random-functions-for-collections.md), [PR #17277](https://github.com/dotnet/fsharp/pull/17277)) + ### Changed * Cache delegate in query extensions. ([PR #17130](https://github.com/dotnet/fsharp/pull/17130)) diff --git a/src/FSharp.Core/FSharp.Core.fsproj b/src/FSharp.Core/FSharp.Core.fsproj index dbfbf0006e6..32aeb2fc498 100644 --- a/src/FSharp.Core/FSharp.Core.fsproj +++ b/src/FSharp.Core/FSharp.Core.fsproj @@ -91,6 +91,12 @@ Primitives/prim-types.fs + + Random/Random.fsi + + + Random/Random.fs + Collections/local.fsi diff --git a/src/FSharp.Core/Random.fs b/src/FSharp.Core/Random.fs new file mode 100644 index 00000000000..72c0c96c49b --- /dev/null +++ b/src/FSharp.Core/Random.fs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Microsoft.FSharp.Core + +open System +open System.Runtime.CompilerServices +open System.Threading + +[] +type internal ThreadSafeRandom() = + + [] + [] + static val mutable private random: Random + + [] + static member private Create() = + ThreadSafeRandom.random <- Random() + ThreadSafeRandom.random + + // Don't pass the returned Random object between threads + static member Shared = + match ThreadSafeRandom.random with + | null -> ThreadSafeRandom.Create() + | random -> random diff --git a/src/FSharp.Core/Random.fsi b/src/FSharp.Core/Random.fsi new file mode 100644 index 00000000000..e65feb415a0 --- /dev/null +++ b/src/FSharp.Core/Random.fsi @@ -0,0 +1,7 @@ +namespace Microsoft.FSharp.Core + +open System + +[] +type internal ThreadSafeRandom = + static member Shared: Random diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index 344d7e3e7cf..77153012a5e 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -1936,6 +1936,211 @@ module Array = result + [] + let randomShuffleWith (random: Random) (source: 'T array) : 'T array = + checkNonNull "random" random + checkNonNull "source" source + + let result = copy source + + Microsoft.FSharp.Primitives.Basics.Random.shuffleArrayInPlaceWith random result + + result + + [] + let randomShuffleBy (randomizer: unit -> float) (source: 'T array) : 'T array = + checkNonNull "source" source + + let result = copy source + + Microsoft.FSharp.Primitives.Basics.Random.shuffleArrayInPlaceBy randomizer result + + result + + [] + let randomShuffle (source: 'T array) : 'T array = + randomShuffleWith ThreadSafeRandom.Shared source + + [] + let randomShuffleInPlaceWith (random: Random) (source: 'T array) = + checkNonNull "random" random + checkNonNull "source" source + + Microsoft.FSharp.Primitives.Basics.Random.shuffleArrayInPlaceWith random source + + [] + let randomShuffleInPlaceBy (randomizer: unit -> float) (source: 'T array) = + checkNonNull "source" source + + Microsoft.FSharp.Primitives.Basics.Random.shuffleArrayInPlaceBy randomizer source + + [] + let randomShuffleInPlace (source: 'T array) = + randomShuffleInPlaceWith ThreadSafeRandom.Shared source + + [] + let randomChoiceWith (random: Random) (source: 'T array) : 'T = + checkNonNull "random" random + checkNonNull "source" source + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString + + let i = random.Next(0, inputLength) + source[i] + + [] + let randomChoiceBy (randomizer: unit -> float) (source: 'T array) : 'T = + checkNonNull "source" source + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString + + let i = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + source[i] + + [] + let randomChoice (source: 'T array) : 'T = + randomChoiceWith ThreadSafeRandom.Shared source + + [] + let randomChoicesWith (random: Random) (count: int) (source: 'T array) : 'T array = + checkNonNull "random" random + checkNonNull "source" source + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString + + let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count + + for i = 0 to count - 1 do + let j = random.Next(0, inputLength) + result[i] <- source[j] + + result + + [] + let randomChoicesBy (randomizer: unit -> float) (count: int) (source: 'T array) : 'T array = + checkNonNull "source" source + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString + + let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count + + for i = 0 to count - 1 do + let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + result[i] <- source[j] + + result + + [] + let randomChoices (count: int) (source: 'T array) : 'T array = + randomChoicesWith ThreadSafeRandom.Shared count source + + [] + let randomSampleWith (random: Random) (count: int) (source: 'T array) : 'T array = + checkNonNull "random" random + checkNonNull "source" source + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString + + if count > inputLength then + invalidArg "count" (SR.GetString(SR.notEnoughElements)) + + let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count + + let setSize = + Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count + + if inputLength <= setSize then + let pool = copy source + + for i = 0 to count - 1 do + let j = random.Next(0, inputLength - i) + result[i] <- pool[j] + pool[j] <- pool[inputLength - i - 1] + else + let selected = HashSet() + + for i = 0 to count - 1 do + let mutable j = random.Next(0, inputLength) + + while not (selected.Add j) do + j <- random.Next(0, inputLength) + + result[i] <- source[j] + + result + + [] + let randomSampleBy (randomizer: unit -> float) (count: int) (source: 'T array) : 'T array = + checkNonNull "source" source + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputArrayEmptyString + + if count > inputLength then + invalidArg "count" (SR.GetString(SR.notEnoughElements)) + + let result = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked count + + // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456 + let setSize = + Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count + + if inputLength <= setSize then + let pool = copy source + + for i = 0 to count - 1 do + let j = + Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i) + + result[i] <- pool[j] + pool[j] <- pool[inputLength - i - 1] + else + let selected = HashSet() + + for i = 0 to count - 1 do + let mutable j = + Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + + while not (selected.Add j) do + j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + + result[i] <- source[j] + + result + + [] + let randomSample (count: int) (source: 'T array) : 'T array = + randomSampleWith ThreadSafeRandom.Shared count source + module Parallel = open System.Threading open System.Threading.Tasks diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 8a5d51f0c9e..8947a2a8d07 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3095,6 +3095,328 @@ module Array = [] val insertManyAt: index: int -> values: seq<'T> -> source: 'T array -> 'T array + /// Return a new array shuffled in a random order. + /// + /// The input array. + /// + /// The result array. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomShuffle + /// + /// Can evaluate to [| 0; 2; 4; 3; 1 |]. + /// + [] + val randomShuffle: source: 'T array -> 'T array + + /// Return a new array shuffled in a random order with the specified Random instance. + /// + /// The Random instance. + /// The input array. + /// + /// The result array. + /// + /// Thrown when the input array is null. + /// Thrown when the random argument is null. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomShuffleWith Random.Shared + /// + /// Can evaluate to [| 0; 2; 4; 3; 1 |]. + /// + [] + val randomShuffleWith: random: Random -> source: 'T array -> 'T array + + /// Return a new array shuffled in a random order using the specified randomizer function. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The input array. + /// + /// The result array. + /// + /// Thrown when the input array is null. + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomShuffleBy Random.Shared.NextDouble + /// + /// Can evaluate to [| 0; 2; 4; 3; 1 |]. + /// + [] + val randomShuffleBy: randomizer: (unit -> float) -> source: 'T array -> 'T array + + /// Sorts input array in a random order by mutating the array in-place. + /// + /// The input array. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomShuffleInPlace + /// + /// After evaluation array can contain [| 0; 2; 4; 3; 1 |]. + /// + [] + val randomShuffleInPlace: source: 'T array -> unit + + /// Sorts input array in a random order with the specified Random instance by mutating the array in-place. + /// + /// The input array. + /// The Random instance. + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomShuffleInPlaceWith Random.Shared + /// + /// After evaluation array can contain [| 0; 2; 4; 3; 1 |]. + /// + [] + val randomShuffleInPlaceWith: random: Random -> source: 'T array -> unit + + /// Sorts input array in a random order using the specified randomizer function by mutating the array in-place. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The input array. + /// + /// Thrown when the input array is null. + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomShuffleInPlaceBy Random.Shared.NextDouble + /// + /// After evaluation array can contain [| 0; 2; 4; 3; 1 |]. + /// + [] + val randomShuffleInPlaceBy: randomizer: (unit -> float) -> source: 'T array -> unit + + /// Returns a random element from the given array. + /// + /// The input array. + /// + /// A randomly selected element from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomChoice + /// + /// Can evaluate to 3. + /// + [] + val randomChoice: source: 'T array -> 'T + + /// Returns a random element from the given array with the specified Random instance. + /// + /// The Random instance. + /// The input array. + /// + /// A randomly selected element from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the random argument is null. + /// Thrown when the input array is empty. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomChoiceWith Random.Shared + /// + /// Can evaluate to 3. + /// + [] + val randomChoiceWith: random: Random -> source: 'T array -> 'T + + /// Returns a random element from the given array using the specified randomizer function. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The input array. + /// + /// A randomly selected element from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomChoiceBy Random.Shared.NextDouble + /// + /// Can evaluate to 3. + /// + [] + val randomChoiceBy: randomizer: (unit -> float) -> source: 'T array -> 'T + + /// Returns an array of random elements from the given array, each element can be selected multiple times. + /// + /// The number of elements to return. + /// The input array. + /// + /// An array of randomly selected elements from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// Thrown when count is less than 0. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomChoices 3 + /// + /// Can evaluate to [| 3; 1; 3 |]. + /// + [] + val randomChoices: count: int -> source: 'T array -> 'T array + + /// Returns an array of random elements from the given array with the specified Random instance, each element can be selected multiple times. + /// + /// The Random instance. + /// The number of elements to return. + /// The input array. + /// + /// An array of randomly selected elements from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the random argument is null. + /// Thrown when the input array is empty. + /// Thrown when count is less than 0. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomChoicesWith Random.Shared 3 + /// + /// Can evaluate to [| 3; 1; 3 |]. + /// + [] + val randomChoicesWith: random: Random -> count: int -> source: 'T array -> 'T array + + /// Returns an array of random elements from the given array using the specified randomizer function, each element can be selected multiple times. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The number of elements to return. + /// The input array. + /// + /// An array of randomly selected elements from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// Thrown when count is less than 0. + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomChoicesBy Random.Shared.NextDouble 3 + /// + /// Can evaluate to [| 3; 1; 3 |]. + /// + [] + val randomChoicesBy: randomizer: (unit -> float) -> count: int -> source: 'T array -> 'T array + + /// Returns a random sample of elements from the given array, each element can be selected only once. + /// + /// The number of elements to return. + /// The input array. + /// + /// An array of randomly selected elements from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input array. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomSample 3 + /// + /// Can evaluate to [| 3; 1; 2 |]. + /// + [] + val randomSample: count: int -> source: 'T array -> 'T array + + /// Returns a random sample of elements from the given array with the specified Random instance, each element can be selected only once. + /// + /// The Random instance. + /// The number of elements to return. + /// The input array. + /// + /// An array of randomly selected elements from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the random argument is null. + /// Thrown when the input array is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input array. + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomSampleWith Random.Shared 3 + /// + /// Can evaluate to [| 3; 1; 2 |]. + /// + [] + val randomSampleWith: random: Random -> count: int -> source: 'T array -> 'T array + + /// Returns a random sample of elements from the given array using the specified randomizer function, each element can be selected only once. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The number of elements to return. + /// The input array. + /// + /// An array of randomly selected elements from the input array. + /// + /// Thrown when the input array is null. + /// Thrown when the input array is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input array. + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [| 0; 1; 2; 3; 4 |] + /// + /// inputs |> Array.randomSampleBy Random.Shared.NextDouble 3 + /// + /// Can evaluate to [| 3; 1; 2 |]. + /// + [] + val randomSampleBy: randomizer: (unit -> float) -> count: int -> source: 'T array -> 'T array + /// Provides parallel operations on arrays module Parallel = diff --git a/src/FSharp.Core/list.fs b/src/FSharp.Core/list.fs index dc81209a8c7..d502107a6da 100644 --- a/src/FSharp.Core/list.fs +++ b/src/FSharp.Core/list.fs @@ -2,6 +2,7 @@ namespace Microsoft.FSharp.Collections +open System open Microsoft.FSharp.Core open Microsoft.FSharp.Core.Operators open Microsoft.FSharp.Core.LanguagePrimitives @@ -987,3 +988,173 @@ module List = coll.AddMany(values) // insert values BEFORE the item at the index coll.AddManyAndClose(curr) + + [] + let randomShuffleWith (random: Random) (source: 'T list) : 'T list = + checkNonNull "random" random + + let tempArray = toArray source + Microsoft.FSharp.Primitives.Basics.Random.shuffleArrayInPlaceWith random tempArray + ofArray tempArray + + [] + let randomShuffleBy (randomizer: unit -> float) (source: 'T list) : 'T list = + let tempArray = toArray source + Microsoft.FSharp.Primitives.Basics.Random.shuffleArrayInPlaceBy randomizer tempArray + ofArray tempArray + + [] + let randomShuffle (source: 'T list) : 'T list = + randomShuffleWith ThreadSafeRandom.Shared source + + [] + let randomChoiceWith (random: Random) (source: 'T list) : 'T = + checkNonNull "random" random + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + let i = random.Next(0, inputLength) + source[i] + + [] + let randomChoiceBy (randomizer: unit -> float) (source: 'T list) : 'T = + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + let i = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + source[i] + + [] + let randomChoice (source: 'T list) : 'T = + randomChoiceWith ThreadSafeRandom.Shared source + + [] + let randomChoicesWith (random: Random) (count: int) (source: 'T list) : 'T list = + checkNonNull "random" random + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + [ + for _ = 0 to count - 1 do + let j = random.Next(0, inputLength) + source[j] + ] + + [] + let randomChoicesBy (randomizer: unit -> float) (count: int) (source: 'T list) : 'T list = + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + [ + for _ = 0 to count - 1 do + let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + source[j] + ] + + [] + let randomChoices (count: int) (source: 'T list) : 'T list = + randomChoicesWith ThreadSafeRandom.Shared count source + + [] + let randomSampleWith (random: Random) (count: int) (source: 'T list) : 'T list = + checkNonNull "random" random + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + if count > inputLength then + invalidArg "count" (SR.GetString(SR.notEnoughElements)) + + // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456 + let setSize = + Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count + + if inputLength <= setSize then + let pool = source |> toArray + + [ + for i = 0 to count - 1 do + let j = random.Next(0, inputLength - i) + let item = pool[j] + pool[j] <- pool[inputLength - i - 1] + item + ] + else + let selected = HashSet() + + [ + for _ = 0 to count - 1 do + let mutable j = random.Next(0, inputLength) + + while not (selected.Add j) do + j <- random.Next(0, inputLength) + + source[j] + ] + + [] + let randomSampleBy (randomizer: unit -> float) (count: int) (source: 'T list) : 'T list = + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let inputLength = source.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + if count > inputLength then + invalidArg "count" (SR.GetString(SR.notEnoughElements)) + + let setSize = + Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count + + if inputLength <= setSize then + let pool = source |> toArray + + [ + for i = 0 to count - 1 do + let j = + Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i) + + let item = pool[j] + pool[j] <- pool[inputLength - i - 1] + item + ] + else + let selected = HashSet() + + [ + for _ = 0 to count - 1 do + let mutable j = + Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + + while not (selected.Add j) do + j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + + source[j] + ] + + [] + let randomSample (count: int) (source: 'T list) : 'T list = + randomSampleWith ThreadSafeRandom.Shared count source diff --git a/src/FSharp.Core/list.fsi b/src/FSharp.Core/list.fsi index 05ff605b247..5393fd14439 100644 --- a/src/FSharp.Core/list.fsi +++ b/src/FSharp.Core/list.fsi @@ -2694,3 +2694,258 @@ module List = /// [] val insertManyAt: index: int -> values: seq<'T> -> source: 'T list -> 'T list + + /// Return a new list shuffled in a random order. + /// + /// The input list. + /// + /// The result list. + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomShuffle + /// Can evaluate to [ 0; 2; 4; 3; 1 ]. + /// + /// + [] + val randomShuffle : source: 'T list -> 'T list + + /// Return a new list shuffled in a random order with the specified Random instance. + /// + /// The Random instance. + /// The input list. + /// + /// The result list. + /// + /// Thrown when the random argument is null. + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomShuffleWith Random.Shared + /// + /// Can evaluate to [ 0; 2; 4; 3; 1 ]. + /// + [] + val randomShuffleWith : random: Random -> source: 'T list -> 'T list + + /// Return a new list shuffled in a random order using the specified randomizer function. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The input list. + /// + /// The result list. + /// + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomShuffleBy Random.Shared.NextDouble + /// + /// Can evaluate to [ 0; 2; 4; 3; 1 ]. + /// + [] + val randomShuffleBy : randomizer: (unit -> float) -> source: 'T list -> 'T list + + /// Returns a random element from the given list. + /// + /// The input list. + /// + /// A randomly selected element from the input list. + /// + /// Thrown when the input list is empty. + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomChoice + /// + /// Can evaluate to 3. + /// + [] + val randomChoice : source: 'T list -> 'T + + /// Returns a random element from the given list with the specified Random instance, each element can be selected multiple times. + /// + /// The Random instance. + /// The input list. + /// + /// A randomly selected element from the input list. + /// + /// Thrown when the random argument is null. + /// Thrown when the input list is empty. + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomChoiceWith Random.Shared + /// + /// Can evaluate to 3. + /// + [] + val randomChoiceWith : random: Random -> source: 'T list -> 'T + + /// Returns a random element from the given list using the specified randomizer function. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The input list. + /// + /// A randomly selected element from the input list. + /// + /// Thrown when the input list is empty. + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomChoiceBy Random.Shared.NextDouble + /// + /// Can evaluate to 3. + /// + [] + val randomChoiceBy : randomizer: (unit -> float) -> source: 'T list -> 'T + + /// Returns a list of random elements from the given list. + /// + /// The number of elements to return. + /// The input list. + /// + /// A list of randomly selected elements from the input list. + /// + /// Thrown when the input list is empty. + /// Thrown when count is less than 0. + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomChoices 3 + /// + /// Can evaluate to [ 3; 1; 3 ]. + /// + [] + val randomChoices : count: int -> source: 'T list -> 'T list + + /// Returns a list of random elements from the given list with the specified Random instance, each element can be selected multiple times. + /// + /// The Random instance. + /// The number of elements to return. + /// The input list. + /// + /// A list of randomly selected elements from the input list. + /// + /// Thrown when the random argument is null. + /// Thrown when the input list is empty. + /// Thrown when count is less than 0. + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> Array.randomChoicesWith Random.Shared 3 + /// + /// Can evaluate to [ 3; 1; 3 ]. + /// + [] + val randomChoicesWith : random: Random -> count: int -> source: 'T list -> 'T list + + /// Returns a list of random elements from the given list using the specified randomizer function. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The number of elements to return. + /// The input list. + /// + /// A list of randomly selected elements from the input list. + /// + /// Thrown when the input list is empty. + /// Thrown when count is less than 0. + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomChoicesBy Random.Shared.NextDouble 3 + /// + /// Can evaluate to [ 3; 1; 3 ]. + /// + [] + val randomChoicesBy : randomizer: (unit -> float) -> count: int -> source: 'T list -> 'T list + + /// Returns a random sample of elements from the given list, each element can be selected only once. + /// + /// The number of elements to return. + /// The input list. + /// + /// A list of randomly selected elements from the input list. + /// + /// Thrown when the input list is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input list. + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomSample 3 + /// + /// Can evaluate to [ 3; 1; 2 ]. + /// + [] + val randomSample : count: int -> source: 'T list -> 'T list + + /// Returns a random sample of elements from the given list with the specified Random instance, each element can be selected only once. + /// + /// The Random instance. + /// The number of elements to return. + /// The input list. + /// + /// A list of randomly selected elements from the input list. + /// + /// Thrown when the random argument is null. + /// Thrown when the input list is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input list. + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomSampleWith Random.Shared 3 + /// + /// Can evaluate to [ 3; 1; 2 ]. + /// + [] + val randomSampleWith : random: Random -> count: int -> source: 'T list -> 'T list + + /// Returns a random sample of elements from the given list using the specified randomizer function, each element can be selected only once. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The number of elements to return. + /// The input list. + /// + /// A list of randomly selected elements from the input list. + /// + /// Thrown when the input list is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input list. + /// Thrown when the randomizer function returns a value outside the range [0, 1). + /// + /// + /// + /// let inputs = [ 0; 1; 2; 3; 4 ] + /// + /// inputs |> List.randomSampleBy Random.Shared.NextDouble 3 + /// + /// Can evaluate to [ 3; 1; 2 ]. + /// + [] + val randomSampleBy : randomizer: (unit -> float) -> count: int -> source: 'T list -> 'T list \ No newline at end of file diff --git a/src/FSharp.Core/local.fs b/src/FSharp.Core/local.fs index 063feb4b243..1e7df3c2ec8 100644 --- a/src/FSharp.Core/local.fs +++ b/src/FSharp.Core/local.fs @@ -1,5 +1,5 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. - +// Copyright © 2001-2023 Python Software Foundation. All Rights Reserved. License: https://docs.python.org/3/license.html#psf-license. Code for getMaxSetSizeForSampling is taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456 namespace Microsoft.FSharp.Core @@ -1199,4 +1199,44 @@ module internal Seq = while (e.MoveNext()) do res <- e.Current ValueSome(res) else - ValueNone \ No newline at end of file + ValueNone + +module internal Random = + open System + + let private executeRandomizer (randomizer: unit -> float) = + let value = randomizer() + if value >= 0.0 && value < 1.0 then + value + else + let argName = nameof randomizer + invalidArgOutOfRangeFmt argName + "{0}\n{1} returned {2}, should be in range [0.0, 1.0)." + [|SR.GetString SR.outOfRange; argName; value|] + + let next (randomizer: unit -> float) (minValue: int) (maxValue: int) = + int ((executeRandomizer randomizer) * float (maxValue - minValue)) + minValue + + let shuffleArrayInPlaceWith (random: Random) (array: array<'T>) = + let inputLength = array.Length + for i = 0 to inputLength - 2 do + let j = random.Next(i, inputLength) + if j <> i then + let temp = array[i] + array[i] <- array[j] + array[j] <- temp + + let shuffleArrayInPlaceBy (randomizer: unit -> float) (array: array<'T>) = + let inputLength = array.Length + for i = 0 to inputLength - 2 do + let j = next randomizer i inputLength + if j <> i then + let temp = array[i] + array[i] <- array[j] + array[j] <- temp + + let getMaxSetSizeForSampling count = + let mutable setSize = 21 + if count > 5 then + setSize <- setSize + (4.0 ** ceil (Math.Log(count * 3 |> float, 4)) |> int) + setSize \ No newline at end of file diff --git a/src/FSharp.Core/local.fsi b/src/FSharp.Core/local.fsi index 1b210474062..9de6b8c8152 100644 --- a/src/FSharp.Core/local.fsi +++ b/src/FSharp.Core/local.fsi @@ -26,6 +26,7 @@ module internal DetailedExceptions = // Definitions internal for this library. namespace Microsoft.FSharp.Primitives.Basics +open System open Microsoft.FSharp.Core open Microsoft.FSharp.Collections @@ -119,5 +120,13 @@ module internal Array = val stableSortInPlace: array: 'T array -> unit when 'T: comparison +module internal Random = + + val next: randomizer: (unit -> float) -> minValue: int -> maxValue: int -> int + val getMaxSetSizeForSampling: count: int -> int + + val shuffleArrayInPlaceWith: random: Random -> array: 'T[] -> unit + val shuffleArrayInPlaceBy: randomizer: (unit -> float) -> array: 'T[] -> unit + module internal Seq = val tryLastV: 'T seq -> 'T ValueOption diff --git a/src/FSharp.Core/seq.fs b/src/FSharp.Core/seq.fs index bfe050f9f7c..35adcdda557 100644 --- a/src/FSharp.Core/seq.fs +++ b/src/FSharp.Core/seq.fs @@ -1938,3 +1938,187 @@ module Seq = if i < index then invalidArg "index" "index must be within bounds of the array" } + + [] + let randomShuffleWith (random: Random) (source: seq<'T>) : seq<'T> = + checkNonNull "random" random + checkNonNull "source" source + + let tempArray = toArray source + Microsoft.FSharp.Primitives.Basics.Random.shuffleArrayInPlaceWith random tempArray + ofArray tempArray + + [] + let randomShuffleBy (randomizer: unit -> float) (source: seq<'T>) : seq<'T> = + checkNonNull "source" source + + let tempArray = toArray source + Microsoft.FSharp.Primitives.Basics.Random.shuffleArrayInPlaceBy randomizer tempArray + ofArray tempArray + + [] + let randomShuffle (source: seq<'T>) : seq<'T> = + randomShuffleWith ThreadSafeRandom.Shared source + + [] + let randomChoiceWith (random: Random) (source: seq<'T>) : 'T = + checkNonNull "random" random + checkNonNull "source" source + + let tempArray = toArray source + let inputLength = tempArray.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + let i = random.Next(0, inputLength) + tempArray[i] + + [] + let randomChoiceBy (randomizer: unit -> float) (source: seq<'T>) : 'T = + checkNonNull "source" source + + let tempArray = toArray source + let inputLength = tempArray.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + let i = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + tempArray[i] + + [] + let randomChoice (source: seq<'T>) : 'T = + randomChoiceWith ThreadSafeRandom.Shared source + + [] + let randomChoicesWith (random: Random) (count: int) (source: seq<'T>) : seq<'T> = + checkNonNull "random" random + checkNonNull "source" source + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let tempArray = toArray source + let inputLength = tempArray.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + seq { + for _ = 0 to count - 1 do + let j = random.Next(0, inputLength) + tempArray[j] + } + + [] + let randomChoicesBy (randomizer: unit -> float) (count: int) (source: seq<'T>) : seq<'T> = + checkNonNull "source" source + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let tempArray = toArray source + let inputLength = tempArray.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + seq { + for _ = 0 to count - 1 do + let j = Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + tempArray[j] + } + + [] + let randomChoices (count: int) (source: seq<'T>) : seq<'T> = + randomChoicesWith ThreadSafeRandom.Shared count source + + [] + let randomSampleWith (random: Random) (count: int) (source: seq<'T>) : seq<'T> = + checkNonNull "random" random + checkNonNull "source" source + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let tempArray = toArray source + let inputLength = tempArray.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + if count > inputLength then + invalidArg "count" (SR.GetString(SR.notEnoughElements)) + + // algorithm taken from https://github.com/python/cpython/blob/69b3e8ea569faabccd74036e3d0e5ec7c0c62a20/Lib/random.py#L363-L456 + let setSize = + Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count + + if inputLength <= setSize then + seq { + for i = 0 to count - 1 do + let j = random.Next(0, inputLength - i) + let item = tempArray[j] + tempArray[j] <- tempArray[inputLength - i - 1] + item + } + else + let selected = HashSet() + + seq { + for _ = 0 to count - 1 do + let mutable j = random.Next(0, inputLength) + + while not (selected.Add j) do + j <- random.Next(0, inputLength) + + tempArray[j] + } + + [] + let randomSampleBy (randomizer: unit -> float) (count: int) (source: seq<'T>) : seq<'T> = + checkNonNull "source" source + + if count < 0 then + invalidArgInputMustBeNonNegative "count" count + + let tempArray = toArray source + let inputLength = tempArray.Length + + if inputLength = 0 then + invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString + + if count > inputLength then + invalidArg "count" (SR.GetString(SR.notEnoughElements)) + + let setSize = + Microsoft.FSharp.Primitives.Basics.Random.getMaxSetSizeForSampling count + + if inputLength <= setSize then + seq { + for i = 0 to count - 1 do + let j = + Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 (inputLength - i) + + let item = tempArray[j] + tempArray[j] <- tempArray[inputLength - i - 1] + item + } + else + let selected = HashSet() + + seq { + for _ = 0 to count - 1 do + let mutable j = + Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + + while not (selected.Add j) do + j <- Microsoft.FSharp.Primitives.Basics.Random.next randomizer 0 inputLength + + tempArray[j] + } + + [] + let randomSample (count: int) (source: seq<'T>) : seq<'T> = + randomSampleWith ThreadSafeRandom.Shared count source diff --git a/src/FSharp.Core/seq.fsi b/src/FSharp.Core/seq.fsi index 4bdf2a54d6d..c1e5a6f0ba9 100644 --- a/src/FSharp.Core/seq.fsi +++ b/src/FSharp.Core/seq.fsi @@ -2935,3 +2935,289 @@ module Seq = /// [] val insertManyAt: index: int -> values: seq<'T> -> source: seq<'T> -> seq<'T> + + /// Return a new sequence shuffled in a random order. + /// + /// The input sequence. + /// + /// The result sequence. + /// + /// Thrown when the input sequence is null. + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomShuffle + /// + /// Can evaluate to seq { 0; 2; 4; 3; 1 }. + /// + [] + val randomShuffle: source: seq<'T> -> seq<'T> + + /// Return a new sequence shuffled in a random order with the specified Random instance. + /// + /// The Random instance. + /// The input sequence. + /// + /// The result sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the random argument is null. + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomShuffleWith Random.Shared + /// + /// Can evaluate to seq { 0; 2; 4; 3; 1 }. + /// + [] + val randomShuffleWith: random: Random -> source: seq<'T> -> seq<'T> + + /// Return a new sequence shuffled in a random order with the specified randomizer function. + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The input sequence. + /// + /// The result sequence. + /// Thrown when the input sequence is null. + /// Thrown when the randomizer function returns a number outside the range [0.0..1.0). + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomShuffleBy Random.Shared.NextDouble + /// + /// Can evaluate to seq { 0; 2; 4; 3; 1 }. + /// + [] + val randomShuffleBy: randomizer: (unit -> float) -> source: seq<'T> -> seq<'T> + + /// + /// Returns a random element from the given sequence. + /// + /// + /// The input sequence. + /// + /// A randomly selected element from the input sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the input sequence is empty. + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomChoice + /// + /// Can evaluate to 3. + /// + [] + val randomChoice: source: seq<'T> -> 'T + + /// + /// Returns a random element from the given sequence with the specified Random instance. + /// + /// + /// The Random instance. + /// The input sequence. + /// + /// A randomly selected element from the input array. + /// + /// Thrown when the input sequence is null. + /// Thrown when the random argument is null. + /// Thrown when the input sequence is empty. + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomChoiceWith Random.Shared + /// + /// Can evaluate to 3. + /// + [] + val randomChoiceWith: random: Random -> source: seq<'T> -> 'T + + /// + /// Returns a random element from the given sequence with the specified randomizer function. + /// + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The input sequence. + /// + /// A randomly selected element from the input sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the input sequence is empty. + /// Thrown when the randomizer function returns a number outside the range [0.0..1.0). + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// let randomizer = Random.Shared.NextDouble + /// + /// inputs |> Seq.randomChoiceBy randomizer + /// + /// Can evaluate to 3. + /// + [] + val randomChoiceBy: randomizer: (unit -> float) -> source: seq<'T> -> 'T + + /// + /// Returns an sequence of random elements from the given sequence, each element can be selected multiple times. + /// + /// + /// The number of elements to return. + /// The input sequence. + /// + /// A sequence of randomly selected elements from the input sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the input sequence is empty. + /// Thrown when count is less than 0. + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomChoices 3 + /// + /// Can evaluate to seq { 3; 1; 3 }. + /// + [] + val randomChoices: count: int -> source: seq<'T> -> seq<'T> + + /// + /// Returns a sequence of random elements from the given sequence with the specified Random instance, each element can be selected multiple times. + /// + /// + /// The Random instance. + /// The number of elements to return. + /// The input sequence. + /// + /// A sequence of randomly selected elements from the input sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the random argument is null. + /// Thrown when the input sequence is empty. + /// Thrown when count is less than 0. + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomChoicesWith Random.Shared 3 + /// + /// Can evaluate to seq { 3; 1; 3 }. + /// + [] + val randomChoicesWith: random: Random -> count: int -> source: seq<'T> -> seq<'T> + + /// + /// Returns a sequence of random elements from the given sequence with the specified randomizer function, each element can be selected multiple times. + /// + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The number of elements to return. + /// The input sequence. + /// + /// A sequence of randomly selected elements from the input sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the input sequence is empty. + /// Thrown when count is less than 0. + /// Thrown when the randomizer function returns a number outside the range [0.0..1.0). + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomChoicesBy Random.Shared.NextDouble 3 + /// + /// Can evaluate to seq { 3; 1; 3 }. + /// + [] + val randomChoicesBy: randomizer: (unit -> float) -> count: int -> source: seq<'T> -> seq<'T> + + /// + /// Returns a random sample of elements from the given sequence, each element can be selected only once. + /// + /// + /// The number of elements to return. + /// The input sequence. + /// + /// A sequence of randomly selected elements from the input sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the input sequence is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input sequence. + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomSample 3 + /// + /// Can evaluate to seq { 3; 1; 2 }. + /// + [] + val randomSample: count: int -> source: seq<'T> -> seq<'T> + + /// + /// Returns a random sample of elements from the given sequence with the specified Random instance, each element can be selected only once. + /// + /// + /// The Random instance. + /// The number of elements to return. + /// The input sequence. + /// + /// A sequence of randomly selected elements from the input sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the random argument is null. + /// Thrown when the input sequence is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input sequence. + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomSampleWith Random.Shared 3 + /// + /// Can evaluate to seq { 3; 1; 2 }. + /// + [] + val randomSampleWith: random: Random -> count: int -> source: seq<'T> -> seq<'T> + + /// + /// Returns a random sample of elements from the given sequence with the specified randomizer function, each element can be selected only once. + /// + /// + /// The randomizer function, must return a float number from [0.0..1.0) range. + /// The number of elements to return. + /// The input sequence. + /// + /// A sequence of randomly selected elements from the input sequence. + /// + /// Thrown when the input sequence is null. + /// Thrown when the input sequence is empty. + /// Thrown when count is less than 0. + /// Thrown when count is greater than the length of the input sequence. + /// Thrown when the randomizer function returns a number outside the range [0.0..1.0). + /// + /// + /// + /// let inputs = seq { 0; 1; 2; 3; 4 } + /// + /// inputs |> Seq.randomSampleBy Random.Shared.NextDouble 3 + /// + /// Can evaluate to seq { 3; 1; 2 }. + /// + [] + val randomSampleBy: randomizer: (unit -> float) -> count: int -> source: seq<'T> -> seq<'T> diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl index bac32123722..e1864618be6 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -126,6 +126,9 @@ Microsoft.FSharp.Collections.ArrayModule: T MaxBy[T,TResult](Microsoft.FSharp.Co Microsoft.FSharp.Collections.ArrayModule: T Max[T](T[]) Microsoft.FSharp.Collections.ArrayModule: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule: T RandomChoiceBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], T[]) +Microsoft.FSharp.Collections.ArrayModule: T RandomChoiceWith[T](System.Random, T[]) +Microsoft.FSharp.Collections.ArrayModule: T RandomChoice[T](T[]) Microsoft.FSharp.Collections.ArrayModule: T ReduceBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) Microsoft.FSharp.Collections.ArrayModule: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) Microsoft.FSharp.Collections.ArrayModule: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) @@ -164,6 +167,15 @@ Microsoft.FSharp.Collections.ArrayModule: T[] InsertManyAt[T](Int32, System.Coll Microsoft.FSharp.Collections.ArrayModule: T[] OfList[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ArrayModule: T[] OfSeq[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.ArrayModule: T[] Permute[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomChoicesBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomChoicesWith[T](System.Random, Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomChoices[T](Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomSampleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomSampleWith[T](System.Random, Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomSample[T](Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomShuffleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomShuffleWith[T](System.Random, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomShuffle[T](T[]) Microsoft.FSharp.Collections.ArrayModule: T[] RemoveAt[T](Int32, T[]) Microsoft.FSharp.Collections.ArrayModule: T[] RemoveManyAt[T](Int32, Int32, T[]) Microsoft.FSharp.Collections.ArrayModule: T[] Replicate[T](Int32, T) @@ -194,6 +206,9 @@ Microsoft.FSharp.Collections.ArrayModule: Void Iterate2[T1,T2](Microsoft.FSharp. Microsoft.FSharp.Collections.ArrayModule: Void IterateIndexed2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,Microsoft.FSharp.Core.Unit]]], T1[], T2[]) Microsoft.FSharp.Collections.ArrayModule: Void IterateIndexed[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit]], T[]) Microsoft.FSharp.Collections.ArrayModule: Void Iterate[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit], T[]) +Microsoft.FSharp.Collections.ArrayModule: Void RandomShuffleInPlaceBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], T[]) +Microsoft.FSharp.Collections.ArrayModule: Void RandomShuffleInPlaceWith[T](System.Random, T[]) +Microsoft.FSharp.Collections.ArrayModule: Void RandomShuffleInPlace[T](T[]) Microsoft.FSharp.Collections.ArrayModule: Void Set[T](T[], Int32, T) Microsoft.FSharp.Collections.ArrayModule: Void SortInPlaceBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule: Void SortInPlaceWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], T[]) @@ -329,6 +344,15 @@ Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] OfArray[T](T[]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] OfSeq[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] Permute[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomChoicesBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomChoicesWith[T](System.Random, Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomChoices[T](Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomSampleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomSampleWith[T](System.Random, Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomSample[T](Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomShuffleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomShuffleWith[T](System.Random, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomShuffle[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RemoveAt[T](Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RemoveManyAt[T](Int32, Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] Replicate[T](Int32, T) @@ -377,6 +401,9 @@ Microsoft.FSharp.Collections.ListModule: T MaxBy[T,TResult](Microsoft.FSharp.Cor Microsoft.FSharp.Collections.ListModule: T Max[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T Min[T](Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: T RandomChoiceBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: T RandomChoiceWith[T](System.Random, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: T RandomChoice[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T ReduceBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], Microsoft.FSharp.Collections.FSharpList`1[T]) @@ -483,6 +510,15 @@ Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1 Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] OfArray[T](T[]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] OfList[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] Permute[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomChoicesBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomChoicesWith[T](System.Random, Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomChoices[T](Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomSampleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomSampleWith[T](System.Random, Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomSample[T](Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomShuffleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomShuffleWith[T](System.Random, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomShuffle[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] ReadOnly[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RemoveAt[T](Int32, System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RemoveManyAt[T](Int32, Int32, System.Collections.Generic.IEnumerable`1[T]) @@ -518,6 +554,9 @@ Microsoft.FSharp.Collections.SeqModule: T MaxBy[T,TResult](Microsoft.FSharp.Core Microsoft.FSharp.Collections.SeqModule: T Max[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T Min[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: T RandomChoiceBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: T RandomChoiceWith[T](System.Random, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: T RandomChoice[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T ReduceBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], System.Collections.Generic.IEnumerable`1[T]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl index 2d02c4cb1bb..92d85ccd98d 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -126,6 +126,9 @@ Microsoft.FSharp.Collections.ArrayModule: T MaxBy[T,TResult](Microsoft.FSharp.Co Microsoft.FSharp.Collections.ArrayModule: T Max[T](T[]) Microsoft.FSharp.Collections.ArrayModule: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], T[]) Microsoft.FSharp.Collections.ArrayModule: T Min[T](T[]) +Microsoft.FSharp.Collections.ArrayModule: T RandomChoiceBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], T[]) +Microsoft.FSharp.Collections.ArrayModule: T RandomChoiceWith[T](System.Random, T[]) +Microsoft.FSharp.Collections.ArrayModule: T RandomChoice[T](T[]) Microsoft.FSharp.Collections.ArrayModule: T ReduceBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) Microsoft.FSharp.Collections.ArrayModule: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) Microsoft.FSharp.Collections.ArrayModule: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], T[]) @@ -164,6 +167,15 @@ Microsoft.FSharp.Collections.ArrayModule: T[] InsertManyAt[T](Int32, System.Coll Microsoft.FSharp.Collections.ArrayModule: T[] OfList[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ArrayModule: T[] OfSeq[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.ArrayModule: T[] Permute[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomChoicesBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomChoicesWith[T](System.Random, Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomChoices[T](Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomSampleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomSampleWith[T](System.Random, Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomSample[T](Int32, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomShuffleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomShuffleWith[T](System.Random, T[]) +Microsoft.FSharp.Collections.ArrayModule: T[] RandomShuffle[T](T[]) Microsoft.FSharp.Collections.ArrayModule: T[] RemoveAt[T](Int32, T[]) Microsoft.FSharp.Collections.ArrayModule: T[] RemoveManyAt[T](Int32, Int32, T[]) Microsoft.FSharp.Collections.ArrayModule: T[] Replicate[T](Int32, T) @@ -194,6 +206,9 @@ Microsoft.FSharp.Collections.ArrayModule: Void Iterate2[T1,T2](Microsoft.FSharp. Microsoft.FSharp.Collections.ArrayModule: Void IterateIndexed2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,Microsoft.FSharp.Core.Unit]]], T1[], T2[]) Microsoft.FSharp.Collections.ArrayModule: Void IterateIndexed[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit]], T[]) Microsoft.FSharp.Collections.ArrayModule: Void Iterate[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit], T[]) +Microsoft.FSharp.Collections.ArrayModule: Void RandomShuffleInPlaceBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], T[]) +Microsoft.FSharp.Collections.ArrayModule: Void RandomShuffleInPlaceWith[T](System.Random, T[]) +Microsoft.FSharp.Collections.ArrayModule: Void RandomShuffleInPlace[T](T[]) Microsoft.FSharp.Collections.ArrayModule: Void Set[T](T[], Int32, T) Microsoft.FSharp.Collections.ArrayModule: Void SortInPlaceBy[T,TKey](Microsoft.FSharp.Core.FSharpFunc`2[T,TKey], T[]) Microsoft.FSharp.Collections.ArrayModule: Void SortInPlaceWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], T[]) @@ -329,6 +344,15 @@ Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] OfArray[T](T[]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] OfSeq[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] Permute[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomChoicesBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomChoicesWith[T](System.Random, Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomChoices[T](Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomSampleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomSampleWith[T](System.Random, Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomSample[T](Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomShuffleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomShuffleWith[T](System.Random, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RandomShuffle[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RemoveAt[T](Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] RemoveManyAt[T](Int32, Int32, Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: Microsoft.FSharp.Collections.FSharpList`1[T] Replicate[T](Int32, T) @@ -377,6 +401,9 @@ Microsoft.FSharp.Collections.ListModule: T MaxBy[T,TResult](Microsoft.FSharp.Cor Microsoft.FSharp.Collections.ListModule: T Max[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T Min[T](Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: T RandomChoiceBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: T RandomChoiceWith[T](System.Random, Microsoft.FSharp.Collections.FSharpList`1[T]) +Microsoft.FSharp.Collections.ListModule: T RandomChoice[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T ReduceBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.ListModule: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], Microsoft.FSharp.Collections.FSharpList`1[T]) @@ -483,6 +510,15 @@ Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1 Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] OfArray[T](T[]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] OfList[T](Microsoft.FSharp.Collections.FSharpList`1[T]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] Permute[T](Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,System.Int32], System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomChoicesBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomChoicesWith[T](System.Random, Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomChoices[T](Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomSampleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomSampleWith[T](System.Random, Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomSample[T](Int32, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomShuffleBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomShuffleWith[T](System.Random, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RandomShuffle[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] ReadOnly[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RemoveAt[T](Int32, System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: System.Collections.Generic.IEnumerable`1[T] RemoveManyAt[T](Int32, Int32, System.Collections.Generic.IEnumerable`1[T]) @@ -518,6 +554,9 @@ Microsoft.FSharp.Collections.SeqModule: T MaxBy[T,TResult](Microsoft.FSharp.Core Microsoft.FSharp.Collections.SeqModule: T Max[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T MinBy[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T Min[T](System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: T RandomChoiceBy[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.Double], System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: T RandomChoiceWith[T](System.Random, System.Collections.Generic.IEnumerable`1[T]) +Microsoft.FSharp.Collections.SeqModule: T RandomChoice[T](System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T ReduceBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T Reduce[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Collections.SeqModule: T Sum$W[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,T]], System.Collections.Generic.IEnumerable`1[T]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs index aa112e0b98b..13590a61f5c 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule.fs @@ -1962,3 +1962,436 @@ type ArrayModule() = Assert.AreEqual(arr.[-4..(-3)], ([||]: int array)) + [] + member _.RandomShuffle() = + let arr = [| 1..20 |] + + let shuffled1 = arr |> Array.randomShuffle + let shuffled2 = arr |> Array.randomShuffle + + Assert.AreNotEqual(shuffled1, arr) + Assert.AreNotEqual(shuffled1, shuffled2) + + [] + member _.RandomShuffleWrongArg() = + let nullArr = null + CheckThrowsArgumentNullException (fun () -> Array.randomShuffle nullArr |> ignore) + + [] + member _.RandomShuffleWith() = + let arr = [| 1..20 |] + + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let shuffle1 = arr |> Array.randomShuffleWith rand1 + let shuffle2 = arr |> Array.randomShuffleWith rand2 + let shuffle3 = arr |> Array.randomShuffleWith rand3 + + Assert.AreEqual(shuffle1, shuffle2) + Assert.AreNotEqual(arr, shuffle1) + Assert.AreNotEqual(shuffle1, shuffle3) + + [] + member _.RandomShuffleWithWrongArg() = + let nullArr = null + let arr = [| 1..20 |] + let nullRand = null + let rand = Random(123) + + CheckThrowsArgumentNullException (fun () -> Array.randomShuffleWith rand nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> Array.randomShuffleWith nullRand arr |> ignore) + + [] + member _.RandomShuffleBy() = + let arr = [| 1..20 |] + + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let shuffle1 = arr |> Array.randomShuffleBy rand1.NextDouble + let shuffle2 = arr |> Array.randomShuffleBy rand2.NextDouble + let shuffle3 = arr |> Array.randomShuffleBy rand3.NextDouble + + Assert.AreEqual(shuffle1, shuffle2) + Assert.AreNotEqual(arr, shuffle1) + Assert.AreNotEqual(shuffle1, shuffle3) + + [] + member _.RandomShuffleByWrongArg() = + let nullArr = null + let arr = [| 1..20 |] + let wrongRandomizers = [ + fun () -> nan + fun () -> 1.0 + fun () -> infinity + ] + let randomizer = Random(123).NextDouble + + CheckThrowsArgumentNullException (fun () -> Array.randomShuffleBy randomizer nullArr |> ignore) + wrongRandomizers |> List.iter (fun wrongRandomizer -> + CheckThrowsArgumentOutOfRangeException (fun () -> Array.randomShuffleBy wrongRandomizer arr |> ignore)) + + [] + member _.RandomShuffleInPlace() = + let arr = [| 1..20 |] + let shuffled1 = [| 1..20 |] + let shuffled2 = [| 1..20 |] + + shuffled1 |> Array.randomShuffleInPlace + shuffled2 |> Array.randomShuffleInPlace + + Assert.AreNotEqual(shuffled1, arr) + Assert.AreNotEqual(shuffled1, shuffled2) + + [] + member _.RandomShuffleInPlaceWrongArg() = + let nullArr = null + + CheckThrowsArgumentNullException (fun () -> Array.randomShuffleInPlace nullArr |> ignore) + + [] + member _.RandomShuffleInPlaceWith() = + let arr = [| 1..20 |] + + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let shuffle1 = [| 1..20 |] + let shuffle2 = [| 1..20 |] + let shuffle3 = [| 1..20 |] + + shuffle1 |> Array.randomShuffleInPlaceWith rand1 + shuffle2 |> Array.randomShuffleInPlaceWith rand2 + shuffle3 |> Array.randomShuffleInPlaceWith rand3 + + Assert.AreEqual(shuffle1, shuffle2) + Assert.AreNotEqual(arr, shuffle1) + Assert.AreNotEqual(shuffle1, shuffle3) + + [] + member _.RandomShuffleInPlaceWithWrongArg() = + let nullArr = null + let arr = [| 1..20 |] + let rand = Random(123) + let nullRand = null + + CheckThrowsArgumentNullException (fun () -> Array.randomShuffleInPlaceWith rand nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> Array.randomShuffleInPlaceWith nullRand arr |> ignore) + + [] + member _.RandomShuffleInPlaceBy() = + let arr = [| 1..20 |] + + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let shuffle1 = [| 1..20 |] + let shuffle2 = [| 1..20 |] + let shuffle3 = [| 1..20 |] + + shuffle1 |> Array.randomShuffleInPlaceBy rand1.NextDouble + shuffle2 |> Array.randomShuffleInPlaceBy rand2.NextDouble + shuffle3 |> Array.randomShuffleInPlaceBy rand3.NextDouble + + Assert.AreEqual(shuffle1, shuffle2) + Assert.AreNotEqual(arr, shuffle1) + Assert.AreNotEqual(shuffle1, shuffle3) + + [] + member _.RandomShuffleInPlaceByWrongArg() = + let nullArr = null + let arr = [| 1..20 |] + let wrongRandomizers = [ + fun () -> nan + fun () -> 1.0 + fun () -> infinity + ] + let randomizer = Random(123).NextDouble + + CheckThrowsArgumentNullException (fun () -> Array.randomShuffleInPlaceBy randomizer nullArr |> ignore) + wrongRandomizers |> List.iter (fun wrongRandomizer -> + CheckThrowsArgumentOutOfRangeException (fun () -> Array.randomShuffleInPlaceBy wrongRandomizer arr |> ignore)) + + [] + member _.RandomChoice() = + let arr = [| 1..5000 |] + + // try choice five times, if all are same, it must be broken + let results = [| + Array.randomChoice arr + Array.randomChoice arr + Array.randomChoice arr + Array.randomChoice arr + Array.randomChoice arr + |] + let allSame = results |> Array.forall (fun x -> x = results.[0]) + Assert.False(allSame) + + [] + member _.RandomChoiceWrongArg() = + let nullArr = null + let emptyArr = [||] + + CheckThrowsArgumentNullException (fun () -> Array.randomChoice nullArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomChoice emptyArr |> ignore) + + [] + member _.RandomChoiceWith() = + let arr = [| 1..5000 |] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choice1 = arr |> Array.randomChoiceWith rand1 + let choice2 = arr |> Array.randomChoiceWith rand2 + let choice3 = arr |> Array.randomChoiceWith rand3 + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoiceWithWrongArg() = + let nullArr = null + let emptyArr = [||] + let arr = [| 1..20 |] + let nullRand = null + let rand = Random(123) + + CheckThrowsArgumentNullException (fun () -> Array.randomChoiceWith rand nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> Array.randomChoiceWith nullRand arr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomChoiceWith rand emptyArr |> ignore) + + [] + member _.RandomChoiceBy() = + let arr = [| 1..5000 |] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choice1 = arr |> Array.randomChoiceBy rand1.NextDouble + let choice2 = arr |> Array.randomChoiceBy rand2.NextDouble + let choice3 = arr |> Array.randomChoiceBy rand3.NextDouble + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoiceByWrongArg() = + let nullArr = null + let emptyArr = [||] + let arr = [| 1..20 |] + let wrongRandomizers = [ + fun () -> nan + fun () -> 1.0 + fun () -> infinity + ] + let randomizer = Random(123).NextDouble + + CheckThrowsArgumentNullException (fun () -> Array.randomChoiceBy randomizer nullArr |> ignore) + wrongRandomizers |> List.iter (fun wrongRandomizer -> + CheckThrowsArgumentOutOfRangeException (fun () -> Array.randomChoiceBy wrongRandomizer arr |> ignore)) + CheckThrowsArgumentException (fun () -> Array.randomChoiceBy randomizer emptyArr |> ignore) + + [] + member _.RandomChoices() = + let arr = [| 1..50 |] + + let choicesLength = 20 + let choice1 = arr |> Array.randomChoices choicesLength + let choice2 = arr |> Array.randomChoices choicesLength + + Assert.AreNotEqual(choice1, choice2) + Assert.AreEqual(choicesLength, choice1.Length) + Assert.AreEqual(choicesLength, choice2.Length) + + let arr = [| 1; 2 |] + let choices = arr |> Array.randomChoices choicesLength + Assert.AreEqual(choicesLength, choices.Length) + Assert.AreEqual(arr, choices |> Array.distinct |> Array.sort) + + [] + member _.RandomChoicesWrongArg() = + let nullArr = null + let emptyArr = [||] + let arr = [| 1..50 |] + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentNullException (fun () -> Array.randomChoices choicesLength nullArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomChoices choicesLength emptyArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomChoices negativeChoicesLength arr |> ignore) + + [] + member _.RandomChoicesWith() = + let arr = [| 1..50 |] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = arr |> Array.randomChoicesWith rand1 choicesLength + let choice2 = arr |> Array.randomChoicesWith rand2 choicesLength + let choice3 = arr |> Array.randomChoicesWith rand3 choicesLength + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoicesWithWrongArg() = + let nullArr = null + let emptyArr = [||] + let arr = [| 1..50 |] + let nullRand = null + let rand = Random(123) + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentNullException (fun () -> Array.randomChoicesWith rand choicesLength nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> Array.randomChoicesWith nullRand choicesLength arr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomChoicesWith rand choicesLength emptyArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomChoicesWith rand negativeChoicesLength arr |> ignore) + + [] + member _.RandomChoicesBy() = + let arr = [| 1..50 |] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = arr |> Array.randomChoicesBy rand1.NextDouble choicesLength + let choice2 = arr |> Array.randomChoicesBy rand2.NextDouble choicesLength + let choice3 = arr |> Array.randomChoicesBy rand3.NextDouble choicesLength + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoicesByWrongArg() = + let nullArr = null + let emptyArr = [||] + let arr = [| 1..50 |] + let wrongRandomizers = [ + fun () -> nan + fun () -> 1.0 + fun () -> infinity + ] + let randomizer = Random(123).NextDouble + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentNullException (fun () -> Array.randomChoicesBy randomizer choicesLength nullArr |> ignore) + wrongRandomizers |> List.iter (fun wrongRandomizer -> + CheckThrowsArgumentOutOfRangeException (fun () -> Array.randomChoicesBy wrongRandomizer choicesLength arr |> ignore)) + CheckThrowsArgumentException (fun () -> Array.randomChoicesBy randomizer choicesLength emptyArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomChoicesBy randomizer negativeChoicesLength arr |> ignore) + + [] + member _.RandomSample() = + let arr = [| 1..50 |] + + let choicesLength = 20 + let choice1 = arr |> Array.randomSample choicesLength + let choice2 = arr |> Array.randomSample choicesLength + + Assert.AreNotEqual(choice1, choice2) + Assert.AreEqual(choicesLength, choice1.Length) + Assert.AreEqual(choicesLength, choice2.Length) + Assert.AreEqual(choice1, choice1 |> Array.distinct) + Assert.AreEqual(choice2, choice2 |> Array.distinct) + + [] + member _.RandomSampleWrongArg() = + let nullArr = null + let emptyArr = [||] + let arr = [| 1..50 |] + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentNullException (fun () -> Array.randomSample sampleLength nullArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomSample sampleLength emptyArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomSample negativeSampleLength arr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomSample tooBigSampleLength arr |> ignore) + + [] + member _.RandomSampleWith() = + let arr = [| 1..50 |] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = arr |> Array.randomSampleWith rand1 choicesLength + let choice2 = arr |> Array.randomSampleWith rand2 choicesLength + let choice3 = arr |> Array.randomSampleWith rand3 choicesLength + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + Assert.AreEqual(choicesLength, choice1.Length) + Assert.AreEqual(choicesLength, choice3.Length) + Assert.AreEqual(choice1, choice1 |> Array.distinct) + Assert.AreEqual(choice3, choice3 |> Array.distinct) + + [] + member _.RandomSampleWithWrongArg() = + let nullArr = null + let emptyArr = [||] + let arr = [| 1..50 |] + let nullRand = null + let rand = Random(123) + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentNullException (fun () -> Array.randomSampleWith rand sampleLength nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> Array.randomSampleWith nullRand sampleLength arr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomSampleWith rand sampleLength emptyArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomSampleWith rand negativeSampleLength arr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomSampleWith rand tooBigSampleLength arr |> ignore) + + [] + member _.RandomSampleBy() = + let arr = [| 1..50 |] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = arr |> Array.randomSampleBy rand1.NextDouble choicesLength + let choice2 = arr |> Array.randomSampleBy rand2.NextDouble choicesLength + let choice3 = arr |> Array.randomSampleBy rand3.NextDouble choicesLength + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + Assert.AreEqual(choicesLength, choice1.Length) + Assert.AreEqual(choicesLength, choice3.Length) + Assert.AreEqual(choice1, choice1 |> Array.distinct) + Assert.AreEqual(choice3, choice3 |> Array.distinct) + + [] + member _.RandomSampleByWrongArg() = + let nullArr = null + let emptyArr = [||] + let arr = [| 1..50 |] + let wrongRandomizers = [ + fun () -> nan + fun () -> 1.0 + fun () -> infinity + ] + let randomizer = Random(123).NextDouble + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentNullException (fun () -> Array.randomSampleBy randomizer sampleLength nullArr |> ignore) + wrongRandomizers |> List.iter (fun wrongRandomizer -> + CheckThrowsArgumentOutOfRangeException (fun () -> Array.randomSampleBy wrongRandomizer sampleLength arr |> ignore)) + CheckThrowsArgumentException (fun () -> Array.randomSampleBy randomizer sampleLength emptyArr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomSampleBy randomizer negativeSampleLength arr |> ignore) + CheckThrowsArgumentException (fun () -> Array.randomSampleBy randomizer tooBigSampleLength arr |> ignore) \ No newline at end of file diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs index fa245c76c87..9f3ae062d02 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ListModule.fs @@ -1086,4 +1086,306 @@ type ListModule() = member _.``Get item with reverse index behaves as expected``() = let list = [1;2;3;4;5] - Assert.AreEqual(list.[^1], 4) \ No newline at end of file + Assert.AreEqual(list.[^1], 4) + + [] + member _.RandomShuffle() = + let list = [ 1..20 ] + + let shuffled1 = list |> List.randomShuffle + let shuffled2 = list |> List.randomShuffle + + Assert.AreNotEqual(shuffled1, list) + Assert.AreNotEqual(shuffled1, shuffled2) + + [] + member _.RandomShuffleWith() = + let arr = [ 1..20 ] + + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let shuffle1 = arr |> List.randomShuffleWith rand1 + let shuffle2 = arr |> List.randomShuffleWith rand2 + let shuffle3 = arr |> List.randomShuffleWith rand3 + + Assert.AreEqual(shuffle1, shuffle2) + Assert.AreNotEqual(arr, shuffle1) + Assert.AreNotEqual(shuffle1, shuffle3) + + [] + member _.RandomShuffleWithWrongArg() = + let list = [ 1..20 ] + let nullRand = null + + CheckThrowsArgumentNullException (fun () -> List.randomShuffleWith nullRand list |> ignore) + + [] + member _.RandomShuffleBy() = + let arr = [ 1..20 ] + + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let shuffle1 = arr |> List.randomShuffleBy rand1.NextDouble + let shuffle2 = arr |> List.randomShuffleBy rand2.NextDouble + let shuffle3 = arr |> List.randomShuffleBy rand3.NextDouble + + Assert.AreEqual(shuffle1, shuffle2) + Assert.AreNotEqual(arr, shuffle1) + Assert.AreNotEqual(shuffle1, shuffle3) + + [] + member _.RandomShuffleByWrongArg() = + let list = [ 1..20 ] + let wrongRandomizer = fun () -> 1.0 + + CheckThrowsArgumentOutOfRangeException (fun () -> List.randomShuffleBy wrongRandomizer list |> ignore) + + [] + member _.RandomChoice() = + let list = [ 1..5000 ] + + // try choice five times, if all are same, it must be broken + let results = [ + List.randomChoice list + List.randomChoice list + List.randomChoice list + List.randomChoice list + List.randomChoice list + ] + let allSame = results |> List.forall (fun x -> x = results.Head) + Assert.False(allSame) + + [] + member _.RandomChoiceWrongArg() = + let emptyList = [] + + CheckThrowsArgumentException (fun () -> List.randomChoice emptyList |> ignore) + + [] + member _.RandomChoiceWith() = + let list = [ 1..5000 ] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choice1 = list |> List.randomChoiceWith rand1 + let choice2 = list |> List.randomChoiceWith rand2 + let choice3 = list |> List.randomChoiceWith rand3 + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoiceWithWrongArg() = + let emptyList = [] + let list = [ 1..20 ] + let nullRand = null + let rand = Random(123) + + CheckThrowsArgumentNullException (fun () -> List.randomChoiceWith nullRand list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomChoiceWith rand emptyList |> ignore) + + [] + member _.RandomChoiceBy() = + let list = [ 1..5000 ] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choice1 = list |> List.randomChoiceBy rand1.NextDouble + let choice2 = list |> List.randomChoiceBy rand2.NextDouble + let choice3 = list |> List.randomChoiceBy rand3.NextDouble + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoiceByWrongArg() = + let emptyList = [] + let list = [ 1..20 ] + let wrongRandomizer = fun () -> 1.0 + let randomizer = Random(123).NextDouble + + CheckThrowsArgumentOutOfRangeException (fun () -> List.randomChoiceBy wrongRandomizer list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomChoiceBy randomizer emptyList |> ignore) + + [] + member _.RandomChoices() = + let list = [ 1..50 ] + + let choicesLength = 20 + let choice1 = list |> List.randomChoices choicesLength + let choice2 = list |> List.randomChoices choicesLength + + Assert.AreNotEqual(choice1, choice2) + Assert.AreEqual(choicesLength, choice1.Length) + Assert.AreEqual(choicesLength, choice2.Length) + + let list = [ 1; 2 ] + let choices = list |> List.randomChoices choicesLength + Assert.AreEqual(choicesLength, choices.Length) + Assert.AreEqual(list, choices |> List.distinct |> List.sort) + + [] + member _.RandomChoicesWrongArg() = + let emptyList = [] + let list = [ 1..50 ] + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentException (fun () -> List.randomChoices choicesLength emptyList |> ignore) + CheckThrowsArgumentException (fun () -> List.randomChoices negativeChoicesLength list |> ignore) + + [] + member _.RandomChoicesWith() = + let list = [ 1..50 ] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = list |> List.randomChoicesWith rand1 choicesLength + let choice2 = list |> List.randomChoicesWith rand2 choicesLength + let choice3 = list |> List.randomChoicesWith rand3 choicesLength + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoicesWithWrongArg() = + let emptyList = [] + let list = [ 1..50 ] + let nullRand = null + let rand = Random(123) + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentNullException (fun () -> List.randomChoicesWith nullRand choicesLength list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomChoicesWith rand choicesLength emptyList |> ignore) + CheckThrowsArgumentException (fun () -> List.randomChoicesWith rand negativeChoicesLength list |> ignore) + + [] + member _.RandomChoicesBy() = + let list = [ 1..50 ] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = list |> List.randomChoicesBy rand1.NextDouble choicesLength + let choice2 = list |> List.randomChoicesBy rand2.NextDouble choicesLength + let choice3 = list |> List.randomChoicesBy rand3.NextDouble choicesLength + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoicesByWrongArg() = + let emptyList = [] + let list = [ 1..50 ] + let wrongRandomizer = fun () -> 1.0 + let randomizer = Random(123).NextDouble + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentOutOfRangeException (fun () -> List.randomChoicesBy wrongRandomizer choicesLength list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomChoicesBy randomizer choicesLength emptyList |> ignore) + CheckThrowsArgumentException (fun () -> List.randomChoicesBy randomizer negativeChoicesLength list |> ignore) + + [] + member _.RandomSample() = + let arr = [ 1..50 ] + + let choicesLength = 20 + let choice1 = arr |> List.randomSample choicesLength + let choice2 = arr |> List.randomSample choicesLength + + Assert.AreNotEqual(choice1, choice2) + Assert.AreEqual(choicesLength, choice1.Length) + Assert.AreEqual(choicesLength, choice2.Length) + Assert.AreEqual(choice1, choice1 |> List.distinct) + Assert.AreEqual(choice2, choice2 |> List.distinct) + + [] + member _.RandomSampleWrongArg() = + let emptyList = [] + let list = [ 1..50 ] + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentException (fun () -> List.randomSample sampleLength emptyList |> ignore) + CheckThrowsArgumentException (fun () -> List.randomSample negativeSampleLength list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomSample tooBigSampleLength list |> ignore) + + [] + member _.RandomSampleWith() = + let list = [ 1..50 ] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = list |> List.randomSampleWith rand1 choicesLength + let choice2 = list |> List.randomSampleWith rand2 choicesLength + let choice3 = list |> List.randomSampleWith rand3 choicesLength + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + Assert.AreEqual(choicesLength, choice1.Length) + Assert.AreEqual(choicesLength, choice3.Length) + Assert.AreEqual(choice1, choice1 |> List.distinct) + Assert.AreEqual(choice3, choice3 |> List.distinct) + + [] + member _.RandomSampleWithWrongArg() = + let emptyArr = [] + let list = [ 1..50 ] + let nullRand = null + let rand = Random(123) + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentNullException (fun () -> List.randomSampleWith nullRand sampleLength list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomSampleWith rand sampleLength emptyArr |> ignore) + CheckThrowsArgumentException (fun () -> List.randomSampleWith rand negativeSampleLength list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomSampleWith rand tooBigSampleLength list |> ignore) + + [] + member _.RandomSampleBy() = + let list = [ 1..50 ] + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = list |> List.randomSampleBy rand1.NextDouble choicesLength + let choice2 = list |> List.randomSampleBy rand2.NextDouble choicesLength + let choice3 = list |> List.randomSampleBy rand3.NextDouble choicesLength + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + Assert.AreEqual(choicesLength, choice1.Length) + Assert.AreEqual(choicesLength, choice3.Length) + Assert.AreEqual(choice1, choice1 |> List.distinct) + Assert.AreEqual(choice3, choice3 |> List.distinct) + + [] + member _.RandomSampleByWrongArg() = + let emptyArr = [] + let list = [ 1..50 ] + let wrongRandomizer = fun () -> 1.0 + let randomizer = Random(123).NextDouble + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentOutOfRangeException (fun () -> List.randomSampleBy wrongRandomizer sampleLength list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomSampleBy randomizer sampleLength emptyArr |> ignore) + CheckThrowsArgumentException (fun () -> List.randomSampleBy randomizer negativeSampleLength list |> ignore) + CheckThrowsArgumentException (fun () -> List.randomSampleBy randomizer tooBigSampleLength list |> ignore) \ No newline at end of file diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs index d80f5404a53..7083ada323c 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/SeqModule.fs @@ -1160,3 +1160,335 @@ type SeqModule() = let nullSeq:seq<'a> = null CheckThrowsArgumentNullException (fun () -> Seq.contains 5 nullSeq |> ignore) + + [] + member _.RandomShuffle() = + let intSeq = seq { 1..20 } + + let shuffled1 = intSeq |> Seq.randomShuffle |> Seq.cache + let shuffled2 = intSeq |> Seq.randomShuffle |> Seq.cache + + Assert.AreNotEqual(shuffled1, intSeq) + Assert.AreNotEqual(shuffled1, shuffled2) + + [] + member _.RandomShuffleWrongArg() = + let nullSeq = null + CheckThrowsArgumentNullException (fun () -> Seq.randomShuffle nullSeq |> ignore) + + [] + member _.RandomShuffleWith() = + let intSeq = seq { 1..20 } + + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let shuffle1 = intSeq |> Seq.randomShuffleWith rand1 |> Seq.cache + let shuffle2 = intSeq |> Seq.randomShuffleWith rand2 |> Seq.cache + let shuffle3 = intSeq |> Seq.randomShuffleWith rand3 |> Seq.cache + + Assert.AreEqual(shuffle1, shuffle2) + Assert.AreNotEqual(intSeq, shuffle1) + Assert.AreNotEqual(shuffle1, shuffle3) + + [] + member _.RandomShuffleWithWrongArg() = + let nullSeq = null + let intSeq = seq { 1..20 } + let nullRand = null + let rand = Random(123) + + CheckThrowsArgumentNullException (fun () -> Seq.randomShuffleWith rand nullSeq |> ignore) + CheckThrowsArgumentNullException (fun () -> Seq.randomShuffleWith nullRand intSeq |> ignore) + + [] + member _.RandomShuffleBy() = + let intSeq = seq { 1..20 } + + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let shuffle1 = intSeq |> Seq.randomShuffleBy rand1.NextDouble |> Seq.cache + let shuffle2 = intSeq |> Seq.randomShuffleBy rand2.NextDouble |> Seq.cache + let shuffle3 = intSeq |> Seq.randomShuffleBy rand3.NextDouble |> Seq.cache + + Assert.AreEqual(shuffle1, shuffle2) + Assert.AreNotEqual(intSeq, shuffle1) + Assert.AreNotEqual(shuffle1, shuffle3) + + [] + member _.RandomShuffleByWrongArg() = + let nullSeq = null + let intSeq = seq { 1..20 } + let wrongRandomizer = fun () -> 1.0 + let randomizer = Random(123).NextDouble + + CheckThrowsArgumentNullException (fun () -> Seq.randomShuffleBy randomizer nullSeq |> ignore) + CheckThrowsArgumentOutOfRangeException (fun () -> Seq.randomShuffleBy wrongRandomizer intSeq |> ignore) + + [] + member _.RandomChoice() = + let intSeq = seq { 1..5000 } + + // try choice five times, if all are same, it must be broken + let results = [| + Seq.randomChoice intSeq + Seq.randomChoice intSeq + Seq.randomChoice intSeq + Seq.randomChoice intSeq + Seq.randomChoice intSeq + |] + let allSame = results |> Array.forall (fun x -> x = results.[0]) + Assert.False(allSame) + + [] + member _.RandomChoiceWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + + CheckThrowsArgumentNullException (fun () -> Seq.randomChoice nullSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoice emptySeq |> ignore) + + [] + member _.RandomChoiceWith() = + let intSeq = seq { 1..5000 } + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choice1 = intSeq |> Seq.randomChoiceWith rand1 + let choice2 = intSeq |> Seq.randomChoiceWith rand2 + let choice3 = intSeq |> Seq.randomChoiceWith rand3 + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoiceWithWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + let intSeq = seq { 1..20 } + let nullRand = null + let rand = Random(123) + + CheckThrowsArgumentNullException (fun () -> Seq.randomChoiceWith rand nullSeq |> ignore) + CheckThrowsArgumentNullException (fun () -> Seq.randomChoiceWith nullRand intSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoiceWith rand emptySeq |> ignore) + + [] + member _.RandomChoiceBy() = + let intSeq = seq { 1..5000 } + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choice1 = intSeq |> Seq.randomChoiceBy rand1.NextDouble + let choice2 = intSeq |> Seq.randomChoiceBy rand2.NextDouble + let choice3 = intSeq |> Seq.randomChoiceBy rand3.NextDouble + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoiceByWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + let intSeq = seq { 1..20 } + let wrongRandomizer = fun () -> 1.0 + let randomizer = Random(123).NextDouble + + CheckThrowsArgumentNullException (fun () -> Seq.randomChoiceBy randomizer nullSeq |> ignore) + CheckThrowsArgumentOutOfRangeException (fun () -> Seq.randomChoiceBy wrongRandomizer intSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoiceBy randomizer emptySeq |> ignore) + + [] + member _.RandomChoices() = + let intSeq = seq { 1..50 } + + let choicesLength = 20 + let choice1 = intSeq |> Seq.randomChoices choicesLength |> Seq.cache + let choice2 = intSeq |> Seq.randomChoices choicesLength |> Seq.cache + + Assert.AreNotEqual(choice1, choice2) + Assert.AreEqual(choicesLength, choice1 |> Seq.length) + Assert.AreEqual(choicesLength, choice2 |> Seq.length) + + let intSeq = seq { 1; 2 } + let choices = intSeq |> Seq.randomChoices choicesLength + Assert.AreEqual(choicesLength, choices |> Seq.length) + Assert.AreEqual(intSeq, choices |> Seq.distinct |> Seq.sort) + + [] + member _.RandomChoicesWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + let intSeq = seq { 1..50 } + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentNullException (fun () -> Seq.randomChoices choicesLength nullSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoices choicesLength emptySeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoices negativeChoicesLength intSeq |> ignore) + + [] + member _.RandomChoicesWith() = + let seq = seq { 1..50 } + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = seq |> Seq.randomChoicesWith rand1 choicesLength |> Seq.cache + let choice2 = seq |> Seq.randomChoicesWith rand2 choicesLength |> Seq.cache + let choice3 = seq |> Seq.randomChoicesWith rand3 choicesLength |> Seq.cache + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoicesWithWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + let intSeq = seq { 1..50 } + let nullRand = null + let rand = Random(123) + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentNullException (fun () -> Seq.randomChoicesWith rand choicesLength nullSeq |> ignore) + CheckThrowsArgumentNullException (fun () -> Seq.randomChoicesWith nullRand choicesLength intSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoicesWith rand choicesLength emptySeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoicesWith rand negativeChoicesLength intSeq |> ignore) + + [] + member _.RandomChoicesBy() = + let seq = seq { 1..50 } + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = seq |> Seq.randomChoicesBy rand1.NextDouble choicesLength |> Seq.cache + let choice2 = seq |> Seq.randomChoicesBy rand2.NextDouble choicesLength |> Seq.cache + let choice3 = seq |> Seq.randomChoicesBy rand3.NextDouble choicesLength |> Seq.cache + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + + [] + member _.RandomChoicesByWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + let intSeq = seq { 1..50 } + let wrongRandomizer = fun () -> 1.0 + let randomizer = Random(123).NextDouble + let choicesLength = 20 + let negativeChoicesLength = -1 + + CheckThrowsArgumentNullException (fun () -> Seq.randomChoicesBy randomizer choicesLength nullSeq |> ignore) + CheckThrowsArgumentOutOfRangeException (fun () -> Seq.randomChoicesBy wrongRandomizer choicesLength intSeq |> Seq.toList |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoicesBy randomizer choicesLength emptySeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomChoicesBy randomizer negativeChoicesLength intSeq |> ignore) + + [] + member _.RandomSample() = + let intSeq = seq { 1..50 } + + let choicesLength = 20 + let choice1 = intSeq |> Seq.randomSample choicesLength |> Seq.cache + let choice2 = intSeq |> Seq.randomSample choicesLength |> Seq.cache + + Assert.AreNotEqual(choice1, choice2) + Assert.AreEqual(choicesLength, choice1 |> Seq.length) + Assert.AreEqual(choicesLength, choice2 |> Seq.length) + + Assert.AreEqual(choice1, choice1 |> Seq.distinct) + Assert.AreEqual(choice2, choice2 |> Seq.distinct) + + [] + member _.RandomSampleWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + let intSeq = seq { 1..50 } + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentNullException (fun () -> Seq.randomSample sampleLength nullSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSample sampleLength emptySeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSample negativeSampleLength intSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSample tooBigSampleLength intSeq |> ignore) + + [] + member _.RandomSampleWith() = + let intSeq = seq { 1..50 } + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = intSeq |> Seq.randomSampleWith rand1 choicesLength |> Seq.cache + let choice2 = intSeq |> Seq.randomSampleWith rand2 choicesLength |> Seq.cache + let choice3 = intSeq |> Seq.randomSampleWith rand3 choicesLength |> Seq.cache + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + Assert.AreEqual(choicesLength, choice1 |> Seq.length) + Assert.AreEqual(choicesLength, choice3 |> Seq.length) + Assert.AreEqual(choice1, choice1 |> Seq.distinct) + Assert.AreEqual(choice3, choice3 |> Seq.distinct) + + [] + member _.RandomSampleWithWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + let intSeq = seq { 1..50 } + let nullRand = null + let rand = Random(123) + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentNullException (fun () -> Seq.randomSampleWith rand sampleLength nullSeq |> ignore) + CheckThrowsArgumentNullException (fun () -> Seq.randomSampleWith nullRand sampleLength intSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSampleWith rand sampleLength emptySeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSampleWith rand negativeSampleLength intSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSampleWith rand tooBigSampleLength intSeq |> ignore) + + [] + member _.RandomSampleBy() = + let intSeq = seq { 1..50 } + let rand1 = Random(123) + let rand2 = Random(123) + let rand3 = Random(321) + + let choicesLength = 20 + let choice1 = intSeq |> Seq.randomSampleBy rand1.NextDouble choicesLength |> Seq.cache + let choice2 = intSeq |> Seq.randomSampleBy rand2.NextDouble choicesLength |> Seq.cache + let choice3 = intSeq |> Seq.randomSampleBy rand3.NextDouble choicesLength |> Seq.cache + + Assert.AreEqual(choice1, choice2) + Assert.AreNotEqual(choice1, choice3) + Assert.AreEqual(choicesLength, choice1 |> Seq.length) + Assert.AreEqual(choicesLength, choice3 |> Seq.length) + Assert.AreEqual(choice1, choice1 |> Seq.distinct) + Assert.AreEqual(choice3, choice3 |> Seq.distinct) + + [] + member _.RandomSampleByWrongArg() = + let nullSeq = null + let emptySeq = Seq.empty + let intSeq = seq { 1..50 } + let wrongRandomizer = fun () -> 1.0 + let randomizer = Random(123).NextDouble + let tooBigSampleLength = 100 + let negativeSampleLength = -1 + let sampleLength = 20 + + CheckThrowsArgumentNullException (fun () -> Seq.randomSampleBy randomizer sampleLength nullSeq |> ignore) + CheckThrowsArgumentOutOfRangeException (fun () -> Seq.randomSampleBy wrongRandomizer sampleLength intSeq |> Seq.toList |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSampleBy randomizer sampleLength emptySeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSampleBy randomizer negativeSampleLength intSeq |> ignore) + CheckThrowsArgumentException (fun () -> Seq.randomSampleBy randomizer tooBigSampleLength intSeq |> ignore) \ No newline at end of file