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