diff --git a/src/FSharp.Core/array.fs b/src/FSharp.Core/array.fs index 8c2fa8470fa..2e8926ec6c6 100644 --- a/src/FSharp.Core/array.fs +++ b/src/FSharp.Core/array.fs @@ -1934,6 +1934,46 @@ module Array = module Parallel = open System.Threading.Tasks + [] + let tryFindIndex predicate (array: _[]) = + checkNonNull "array" array + + let pResult = + Parallel.For( + 0, + array.Length, + (fun i pState -> + if predicate array[i] then + pState.Break()) + ) + + pResult.LowestBreakIteration |> Option.ofNullable |> Option.map int + + [] + let tryFind predicate (array: _[]) = + array |> tryFindIndex predicate |> Option.map (fun i -> array[i]) + + [] + let tryPick chooser (array: _[]) = + checkNonNull "array" array + let allChosen = new System.Collections.Concurrent.ConcurrentDictionary<_, _>() + + let pResult = + Parallel.For( + 0, + array.Length, + (fun i pState -> + match chooser array[i] with + | None -> () + | chosenElement -> + allChosen[i] <- chosenElement + pState.Break()) + ) + + pResult.LowestBreakIteration + |> Option.ofNullable + |> Option.bind (fun i -> allChosen[int i]) + [] let choose chooser (array: 'T[]) = checkNonNull "array" array diff --git a/src/FSharp.Core/array.fsi b/src/FSharp.Core/array.fsi index 2d08d1116e1..d05ecacc0b3 100644 --- a/src/FSharp.Core/array.fsi +++ b/src/FSharp.Core/array.fsi @@ -3094,6 +3094,102 @@ module Array = /// Provides parallel operations on arrays module Parallel = + /// Returns the first element for which the given function returns True. + /// Returns None if no such element exists. + /// + /// The function to test the input elements. + /// The input array. + /// + /// The first element that satisfies the predicate, or None. + /// + /// Thrown when the input array is null. + /// + /// Try to find the first even number: + /// + /// let inputs = [| 1; 2; 3 |] + /// + /// inputs |> Array.Parallel.tryFind (fun elm -> elm % 2 = 0) + /// + /// Evaluates to Some 2. + /// + /// + /// Try to find the first even number: + /// + /// let inputs = [| 1; 5; 3 |] + /// + /// inputs |> Array.Parallel.tryFind (fun elm -> elm % 2 = 0) + /// + /// Evaluates to None + /// + [] + [] + val tryFind: predicate:('T -> bool) -> array:'T[] -> 'T option + + + /// Returns the index of the first element in the array + /// that satisfies the given predicate. + /// Returns None if no such element exists. + /// The function to test the input elements. + /// The input array. + /// + /// Thrown when the input array is null. + /// + /// The index of the first element that satisfies the predicate, or None. + /// + /// Try to find the index of the first even number: + /// + /// let inputs = [| 1; 2; 3; 4; 5 |] + /// + /// inputs |> Array.Parallel.tryFindIndex (fun elm -> elm % 2 = 0) + /// + /// Evaluates to Some 1 + /// + /// + /// Try to find the index of the first even number: + /// + /// let inputs = [| 1; 3; 5; 7 |] + /// + /// inputs |> Array.Parallel.tryFindIndex (fun elm -> elm % 2 = 0) + /// + /// Evaluates to None + /// + [] + [] + val tryFindIndex : predicate:('T -> bool) -> array:'T[] -> int option + + /// Applies the given function to successive elements, returning the first + /// result where the function returns Some(x) for some x. If the function + /// never returns Some(x) then None is returned. + /// + /// The function to transform the array elements into options. + /// The input array. + /// + /// The first transformed element that is Some(x). + /// + /// Thrown when the input array is null. + /// + /// + /// + /// let input = [| 1; 2; 3 |] + /// + /// input |> Array.Parallel.tryPick (fun n -> if n % 2 = 0 then Some (string n) else None) + /// + /// Evaluates to Some 2. + /// + /// + /// + /// + /// let input = [| 1; 2; 3 |] + /// + /// input |> Array.Parallel.tryPick (fun n -> if n > 3 = 0 then Some (string n) else None) + /// + /// Evaluates to None. + /// + /// + [] + [] + val tryPick: chooser:('T -> 'U option) -> array:'T[] -> 'U option + /// Apply the given function to each element of the array. Return /// the array comprised of the results x for each element where /// the function returns Some(x). diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl index 348c413de1b..783f3bc30aa 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.debug.bsl @@ -40,6 +40,9 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], 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 2d5ddb40c7a..bca7a6bb25a 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard20.release.bsl @@ -40,6 +40,9 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], T[]) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl index 45805d53ae0..614ec47f2d7 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.debug.bsl @@ -40,6 +40,9 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], 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 275087e02e0..702f3302cee 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl +++ b/tests/FSharp.Core.UnitTests/FSharp.Core.SurfaceArea.netstandard21.release.bsl @@ -40,6 +40,9 @@ Microsoft.FSharp.Collections.Array4DModule: T[,,,] Create[T](Int32, Int32, Int32 Microsoft.FSharp.Collections.Array4DModule: T[,,,] Initialize[T](Int32, Int32, Int32, Int32, Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,Microsoft.FSharp.Core.FSharpFunc`2[System.Int32,T]]]]) Microsoft.FSharp.Collections.Array4DModule: T[,,,] ZeroCreate[T](Int32, Int32, Int32, Int32) Microsoft.FSharp.Collections.Array4DModule: Void Set[T](T[,,,], Int32, Int32, Int32, Int32, T) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[System.Int32] TryFindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[TResult] TryPick[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) +Microsoft.FSharp.Collections.ArrayModule+Parallel: Microsoft.FSharp.Core.FSharpOption`1[T] TryFind[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: System.Tuple`2[T[],T[]] Partition[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Choose[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], T[]) Microsoft.FSharp.Collections.ArrayModule+Parallel: TResult[] Collect[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult[]], 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 3d9185468d9..2c68635b3b9 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 @@ -955,17 +955,16 @@ type ArrayModule() = let intArr = [| 1..10 |] let seq = Array.toSeq intArr let sum = Seq.sum seq - Assert.AreEqual(55, sum) - - [] - member this.TryPick() = + Assert.AreEqual(55, sum) + + member private _.TryPickTester tryPickInt tryPickString = // integer array let intArr = [| 1..10 |] let funcInt x = match x with | _ when x % 3 = 0 -> Some (x.ToString()) | _ -> None - let resultInt = Array.tryPick funcInt intArr + let resultInt = tryPickInt funcInt intArr if resultInt <> Some "3" then Assert.Fail() // string array @@ -974,20 +973,26 @@ type ArrayModule() = match x with | "good" -> Some (x.ToString()) | _ -> None - let resultStr = Array.tryPick funcStr strArr + let resultStr = tryPickString funcStr strArr if resultStr <> None then Assert.Fail() // empty array let emptyArr:int[] = [| |] - let resultEpt = Array.tryPick funcInt emptyArr + let resultEpt = tryPickInt funcInt emptyArr if resultEpt <> None then Assert.Fail() // null array let nullArr = null:string[] - CheckThrowsArgumentNullException (fun () -> Array.tryPick funcStr nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> tryPickString funcStr nullArr |> ignore) () + [] + member this.TryPick() = this.TryPickTester Array.tryPick Array.tryPick + + [] + member this.ParallelTryPick() = this.TryPickTester Array.Parallel.tryPick Array.Parallel.tryPick + [] member this.Fold() = // integer array diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs index 23510ddb781..b10ce17fb2e 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/ArrayModule2.fs @@ -972,25 +972,31 @@ type ArrayModule2() = () - [] - member this.TryFind() = + member private _.TryFindTester tryFindInts tryFindStrings = // integer array - let resultInt = [|1..10|] |> Array.tryFind (fun x -> x%7 = 0) + let resultInt = [|1..10|] |> tryFindInts (fun x -> x%7 = 0) if resultInt <> Some 7 then Assert.Fail() // string array - let resultStr = [|"Lists"; "are"; "commonly" ; "list" |] |> Array.tryFind (fun (x:string) -> x.Length > 4) + let resultStr = [|"Lists"; "are"; "commonly" ; "list" |] |> tryFindStrings (fun (x:string) -> x.Length > 4) if resultStr <> Some "Lists" then Assert.Fail() // empty array - let resultEpt =[||] |> Array.tryFind (fun x -> x%7 = 0) + let resultEpt =[||] |> tryFindInts (fun x -> x%7 = 0) if resultEpt <> None then Assert.Fail() // null array let nullArr = null:string[] - CheckThrowsArgumentNullException (fun () -> Array.tryFind (fun (x:string) -> x.Length > 4) nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> tryFindStrings (fun (x:string) -> x.Length > 4) nullArr |> ignore) () + + [] + member this.TryFind() = this.TryFindTester Array.tryFind Array.tryFind + + [] + member this.ParallelTryFind() = this.TryFindTester Array.Parallel.tryFind Array.Parallel.tryFind + [] member this.TryFindBack() = @@ -1016,26 +1022,30 @@ type ArrayModule2() = () - [] - member this.TryFindIndex() = + member private _.TryFindIndexTester tryFindIdxInt tryFindIdxString = // integer array - let resultInt = [|1..10|] |> Array.tryFindIndex (fun x -> x%7 = 0) + let resultInt = [|1..10|] |> tryFindIdxInt (fun x -> x%7 = 0) if resultInt <> Some 6 then Assert.Fail() // string array - let resultStr = [|"Lists"; "are"; "commonly" ; "list" |] |> Array.tryFindIndex (fun (x:string) -> x.Length > 4) + let resultStr = [|"Lists"; "are"; "commonly" ; "list" |] |> tryFindIdxString (fun (x:string) -> x.Length > 4) if resultStr <> Some 0 then Assert.Fail() // empty array - let resultEpt =[||] |> Array.tryFindIndex (fun x -> x % 7 = 0) + let resultEpt =[||] |> tryFindIdxInt (fun x -> x % 7 = 0) if resultEpt <> None then Assert.Fail() // null array let nullArr = null:string[] - CheckThrowsArgumentNullException (fun () -> Array.tryFindIndex (fun (x:string) -> x.Length > 4) nullArr |> ignore) + CheckThrowsArgumentNullException (fun () -> tryFindIdxString (fun (x:string) -> x.Length > 4) nullArr |> ignore) () + [] + member this.TryFindIndex() = this.TryFindIndexTester Array.tryFindIndex Array.tryFindIndex + + [] + member this.ParallelTryFindIndex() = this.TryFindIndexTester Array.Parallel.tryFindIndex Array.Parallel.tryFindIndex [] member this.TryFindIndexBack() = // integer array diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs index 1560c16b564..0494f9682d4 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/Microsoft.FSharp.Collections/CollectionModulesConsistency.fs @@ -14,6 +14,9 @@ let consistency name sqs ls arr = (sqs = arr) |@ (sprintf "Seq.%s = '%A', Array.%s = '%A'" name sqs name arr) .&. (ls = arr) |@ (sprintf "List.%s = '%A', Array.%s = '%A'" name ls name arr) +let consistencyIncludingParallel name sqs ls arr paraArr = + consistency name sqs ls arr .&. + (paraArr = arr) |@ (sprintf "Parallel.%s = '%A', Array.%s = '%A'" name paraArr name arr) let allPairs<'a when 'a : equality> (xs : list<'a>) (xs2 : list<'a>) = let s = xs |> Seq.allPairs xs2 |> Seq.toArray @@ -1104,7 +1107,8 @@ let tryFind<'a when 'a : equality> (xs : 'a []) predicate = let s = xs |> Seq.tryFind predicate let l = xs |> List.ofArray |> List.tryFind predicate let a = xs |> Array.tryFind predicate - consistency "tryFind" s l a + let pa = xs |> Array.Parallel.tryFind predicate + consistencyIncludingParallel "tryFind" s l a pa [] let ``tryFind is consistent`` () = @@ -1128,7 +1132,8 @@ let tryFindIndex<'a when 'a : equality> (xs : 'a []) predicate = let s = xs |> Seq.tryFindIndex predicate let l = xs |> List.ofArray |> List.tryFindIndex predicate let a = xs |> Array.tryFindIndex predicate - consistency "tryFindIndex" s l a + let pa = xs |> Array.Parallel.tryFindIndex predicate + consistencyIncludingParallel "tryFindIndex" s l a pa [] let ``tryFindIndex is consistent`` () = @@ -1188,7 +1193,8 @@ let tryPick<'a when 'a : comparison> (xs : 'a []) f = let s = xs |> Seq.tryPick f let l = xs |> List.ofArray |> List.tryPick f let a = xs |> Array.tryPick f - consistency "tryPick" s l a + let pa = xs |> Array.Parallel.tryPick f + consistencyIncludingParallel "tryPick" s l a pa [] let ``tryPick is consistent`` () =