From 1d13c8b0e8d3382f1af0df6521b248ce295f449d Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Wed, 19 May 2021 14:33:36 +0300 Subject: [PATCH 01/19] flat list - first set of missing array APIs --- src/FSharp.Collections.Immutable/flat-list.fs | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 5f86c40..1bbeddf 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -16,6 +16,7 @@ module FlatList = let inline internal checkNotDefault argName (list : FlatList<'T>) = if list.IsDefault then invalidArg argName "Uninstantiated ImmutableArray/FlatList" let inline internal check (list : FlatList<'T>) = checkNotDefault (nameof list) list + let inline internal checkEmpty (list : FlatList<_>) = check list; if list.Length = 0 then invalidArg (nameof list) "Source is empty" else () ////////// Creating ////////// @@ -131,6 +132,8 @@ module FlatList = let sortWith comparer list = sortWithComparer (ComparisonIdentity.FromFunction comparer) list let sort list = check list; list.Sort() + let get (list:FlatList<_>) index = list.[index] + ////////// Loop-based ////////// let inline private builderWithLengthOf list = builderWith <| length list @@ -400,6 +403,14 @@ module FlatList = if predicate list.[i] then Some list.[i] else loop (i+1) loop <| length list - 1 + let findIndex predicate list = + check list + let len = length list + let rec loop i = + if i > len then indexNotFound() else + if predicate list.[i] then i else loop (i + 1) + loop 0 + let findIndexBack predicate list = check list let rec loop i = @@ -413,6 +424,63 @@ module FlatList = if i < 0 then None else if predicate list.[i] then Some i else loop (i - 1) loop <| length list - 1 + + let fold (folder : 'state -> 'a -> 'state) (state: 'state) (list:FlatList<'a>) = + check list + let mutable result = state + for i = 0 to length list do + result <- folder result list.[i] + result + + let foldBack (folder : 'state -> 'a -> 'state) (list:FlatList<'a>) (state: 'state) = + check list + let mutable result = state + for i = length list - 1 downto 0 do + result <- folder result list.[i] + result + + let reduce (reduction : 'a -> 'a -> 'a) (list:FlatList<'a>) = + checkEmpty list + let mutable result = list.[0] + for i = 1 to length list do + result <- reduction result list.[i] + result + + let reduceBack (reduction : 'a -> 'a -> 'a) (list:FlatList<'a>) = + checkEmpty list + let mutable result = list.[list.Length - 1] + for i = length list - 2 downto 0 do + result <- reduction result list.[i] + result + + let mapFold (mapping:'State -> 'T -> 'Result * 'State) (state:'State) (list:FlatList<'T>) : 'Result[] * 'State = + check list + raise (new System.NotImplementedException()) + + let mapFoldBack (mapping:'State -> 'T -> 'Result * 'State) (list:FlatList<'T>) (state:'State) : 'Result[] * 'State = + check list + raise (new System.NotImplementedException()) + + let zip (left:FlatList<_>) (right:FlatList<_>) = + check left; check right + let len = max (length left) (length right) + let builder = builderWith len + for i = 0 to len do + builder.Add (left.[i], right.[i]) + ofBuilder builder + + let zip3 (left:FlatList<_>) (middle:FlatList<_>) (right:FlatList<_>) = + check left; check middle; check right + let len = length middle |> max (length left) |> max (length right) + let builder = builderWith len + for i = 0 to len do + builder.Add (left.[i], middle.[i], right.[i]) + ofBuilder builder + + let windowed windowSize (list:FlatList<_>) = + check list + raise (new System.NotImplementedException()) + // TODO: windowed ////////// Based on other operations ////////// @@ -469,6 +537,36 @@ module FlatList = f builder moveFromBuilder builder + let inline sum ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = + check list + reduce (+) list + + let inline sumBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = + check list + list |> map projection |> reduce (+) + + let inline average ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = + check list + let len = length list + let sum = sum list + LanguagePrimitives.DivideByInt sum len + + let inline averageBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = + check list + let len = length list + let sum = list |> map projection |> sum + LanguagePrimitives.DivideByInt sum len + + let maxBy projection (list:FlatList<'a> when 'a : comparison) = check list; list |> map projection |> reduce max + let minBy projection (list:FlatList<'a> when 'a : comparison) = check list; list |> map projection |> reduce min + let max (list:FlatList<'a> when 'a : comparison) = check list; reduce max list + let min (list:FlatList<'a> when 'a : comparison) = check list; reduce min list + + let sortBy projection (list:FlatList<'a>) = list |> map projection |> sort + let sortInPlaceBy = sortBy + let sortInPlaceWith = sortWith + let sortInPlace = sort + ////////// module ImmutableArray = FlatList From f2b637d248985fddf6fde8db0a9c9647edc6b817 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Wed, 19 May 2021 14:41:02 +0300 Subject: [PATCH 02/19] flat list - fix mapFold(+Back) and for loops --- src/FSharp.Collections.Immutable/flat-list.fs | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 1bbeddf..b3dff46 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -428,8 +428,8 @@ module FlatList = let fold (folder : 'state -> 'a -> 'state) (state: 'state) (list:FlatList<'a>) = check list let mutable result = state - for i = 0 to length list do - result <- folder result list.[i] + for item in list do + result <- folder result item result let foldBack (folder : 'state -> 'a -> 'state) (list:FlatList<'a>) (state: 'state) = @@ -442,7 +442,7 @@ module FlatList = let reduce (reduction : 'a -> 'a -> 'a) (list:FlatList<'a>) = checkEmpty list let mutable result = list.[0] - for i = 1 to length list do + for i = 1 to length list - 1 do result <- reduction result list.[i] result @@ -453,13 +453,25 @@ module FlatList = result <- reduction result list.[i] result - let mapFold (mapping:'State -> 'T -> 'Result * 'State) (state:'State) (list:FlatList<'T>) : 'Result[] * 'State = + let mapFold (mapping:'State -> 'T -> 'Result * 'State) (state:'State) (list:FlatList<'T>) = check list - raise (new System.NotImplementedException()) + let builder = builderWithLengthOf list + let mutable outState = state + for item in list do + let item, newState = mapping outState item + builder.Add item + outState <- newState + ofBuilder builder, outState - let mapFoldBack (mapping:'State -> 'T -> 'Result * 'State) (list:FlatList<'T>) (state:'State) : 'Result[] * 'State = + let mapFoldBack (mapping:'State -> 'T -> 'Result * 'State) (list:FlatList<'T>) (state:'State) = check list - raise (new System.NotImplementedException()) + let builder = builderWithLengthOf list + let mutable outState = state + for i = length list - 1 downto 0 do + let item, newState = mapping outState list.[i] + builder.Add item + outState <- newState + ofBuilder builder, outState let zip (left:FlatList<_>) (right:FlatList<_>) = check left; check right From f68ab1c797b6c45b1127a68ccb4153970e97e208 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Wed, 19 May 2021 14:46:22 +0300 Subject: [PATCH 03/19] flat list - add unzip --- src/FSharp.Collections.Immutable/flat-list.fs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index b3dff46..94738b5 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -488,7 +488,31 @@ module FlatList = for i = 0 to len do builder.Add (left.[i], middle.[i], right.[i]) ofBuilder builder - + + let internal fst (a, _) = a + let internal snd (_, a) = a + let internal fst3 (a, _, _) = a + let internal snd3 (_, a, _) = a + let internal thd3 (_, _, a) = a + + let unzip (list:FlatList<'a*'b>) = + let left = builderWithLengthOf list + let right = builderWithLengthOf list + for item in list do + left.Add <| fst item + right.Add <| snd item + left, right + + let unzip3 (list:FlatList<'a*'b*'c>) = + let left = builderWithLengthOf list + let right = builderWithLengthOf list + let middle = builderWithLengthOf list + for item in list do + left.Add <| fst3 item + middle.Add <| snd3 item + right.Add <| thd3 item + left, right + let windowed windowSize (list:FlatList<_>) = check list raise (new System.NotImplementedException()) From 96466f7886621f4ae194466f0d14bf5eb23dd8c9 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Wed, 19 May 2021 14:57:53 +0300 Subject: [PATCH 04/19] flat list - find index, unfold, remove excessions --- src/FSharp.Collections.Immutable/flat-list.fs | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 94738b5..2d9faa7 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -407,7 +407,7 @@ module FlatList = check list let len = length list let rec loop i = - if i > len then indexNotFound() else + if i = len then indexNotFound() else if predicate list.[i] then i else loop (i + 1) loop 0 @@ -418,6 +418,14 @@ module FlatList = if predicate list.[i] then i else loop (i - 1) loop <| length list - 1 + let tryFindIndex predicate list = + check list + let len = length list + let rec loop i = + if i = len then None else + if predicate list.[i] then Some i else loop (i + 1) + loop <| 0 + let tryFindIndexBack predicate list = check list let rec loop i = @@ -438,6 +446,16 @@ module FlatList = for i = length list - 1 downto 0 do result <- folder result list.[i] result + + let unfold (generator: 'state -> ('a * 'state) option) state = + let builder = FlatListFactory.CreateBuilder() + let mutable s = state + let mutable step = generator s + while step.IsSome do + s <- snd step.Value + fst step.Value |> builder.Add + step <- generator s + ofBuilder builder let reduce (reduction : 'a -> 'a -> 'a) (list:FlatList<'a>) = checkEmpty list @@ -489,8 +507,6 @@ module FlatList = builder.Add (left.[i], middle.[i], right.[i]) ofBuilder builder - let internal fst (a, _) = a - let internal snd (_, a) = a let internal fst3 (a, _, _) = a let internal snd3 (_, a, _) = a let internal thd3 (_, _, a) = a From 6ce003bdae3856591ea35d46eb8d61bb0fc0e690 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Wed, 19 May 2021 16:58:35 +0300 Subject: [PATCH 05/19] flat list - another changes pack - conversions - plain distinct based on distinctBy - scans and folds - signatures simplifications - fix unzip3 - sorting/comparing --- src/FSharp.Collections.Immutable/flat-list.fs | 81 +++++++++++++++---- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 2d9faa7..198b94a 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -22,12 +22,15 @@ module FlatList = let inline empty<'T> : FlatList<_> = FlatListFactory.Create<'T>() let inline singleton<'T> (item : 'T) : FlatList<'T> = FlatListFactory.Create<'T> (item) + let copy (list:FlatList<_>) = FlatListFactory.CreateRange list let inline ofSeq source = FlatListFactory.CreateRange source let inline ofArray (source : _ array) = FlatListFactory.CreateRange source + let inline ofList (source: _ list) = FlatListFactory.CreateRange source let inline toSeq (flatList: FlatList<_>) = flatList :> seq<_> let inline toArray (list : FlatList<_>) = check list; Seq.toArray list + let inline toList list = check list; Seq.toList list ////////// Building ////////// @@ -201,18 +204,17 @@ module FlatList = for i = 0 to len - 1 do f.Invoke(list1.[i], list2.[i]) - let distinctBy projection (list: FlatList<'T>) = + let distinct (list: FlatList<'T>) = let builder: FlatList<'T>.Builder = builderWith <| length list - let set = System.Collections.Generic.HashSet<'Key>(HashIdentity.Structural) - let mutable outputIndex = 0 + let set = System.Collections.Generic.HashSet<'T>(HashIdentity.Structural) - for i = 0 to length list - 1 do - let item = list.[i] - if set.Add <| projection item then - outputIndex <- outputIndex + 1 + for item in list do + if set.Add item then Builder.add item builder ofBuilder builder + + let distinctBy projection (list:FlatList<'a>) = distinct list |> map projection let map2 mapping list1 list2 = checkNotDefault (nameof list1) list1 @@ -433,19 +435,57 @@ module FlatList = if predicate list.[i] then Some i else loop (i - 1) loop <| length list - 1 - let fold (folder : 'state -> 'a -> 'state) (state: 'state) (list:FlatList<'a>) = + let fold folder (state: 'state) (list:FlatList<'a>) = check list let mutable result = state for item in list do result <- folder result item result - let foldBack (folder : 'state -> 'a -> 'state) (list:FlatList<'a>) (state: 'state) = + let scan folder (state: 'state) (list:FlatList<'a>) = + check list + let mutable s = state + let result = builderWithLengthOf list + result.Add s + for item in list do + s <- folder s item + result.Add s + result + + let fold2 folder (state: 'state) (left:FlatList<'a>) (right:FlatList<'b>) = + check left + let mutable result = state + let len = length left |> max (length right) + for i = 0 to len - 1 do + result <- folder result left.[i] right.[i] + result + + let foldBack2 folder (left:FlatList<'a>) (right:FlatList<'b>) (state:'state) = + check left + let mutable result = state + let leftLen = length left + let rightLen = length right + let len = max leftLen rightLen + for i = 0 to len - 1 do + result <- folder result left.[leftLen - i] right.[rightLen - i] + result + + let foldBack folder (list:FlatList<'a>) (state: 'state) = check list let mutable result = state for i = length list - 1 downto 0 do result <- folder result list.[i] result + + let scanBack folder (list:FlatList<'a>) (state: 'state) = + check list + let mutable s = state + let result = builderWithLengthOf list + result.Add s + for i = length list - 1 downto 0 do + s <- folder s list.[i] + result.Add s + result let unfold (generator: 'state -> ('a * 'state) option) state = let builder = FlatListFactory.CreateBuilder() @@ -457,21 +497,21 @@ module FlatList = step <- generator s ofBuilder builder - let reduce (reduction : 'a -> 'a -> 'a) (list:FlatList<'a>) = + let reduce reduction (list:FlatList<'a>) = checkEmpty list let mutable result = list.[0] for i = 1 to length list - 1 do result <- reduction result list.[i] result - let reduceBack (reduction : 'a -> 'a -> 'a) (list:FlatList<'a>) = + let reduceBack reduction (list:FlatList<'a>) = checkEmpty list let mutable result = list.[list.Length - 1] for i = length list - 2 downto 0 do result <- reduction result list.[i] result - let mapFold (mapping:'State -> 'T -> 'Result * 'State) (state:'State) (list:FlatList<'T>) = + let mapFold mapping (state:'State) (list:FlatList<'T>) = check list let builder = builderWithLengthOf list let mutable outState = state @@ -481,7 +521,7 @@ module FlatList = outState <- newState ofBuilder builder, outState - let mapFoldBack (mapping:'State -> 'T -> 'Result * 'State) (list:FlatList<'T>) (state:'State) = + let mapFoldBack mapping (list:FlatList<'T>) (state:'State) = check list let builder = builderWithLengthOf list let mutable outState = state @@ -511,7 +551,7 @@ module FlatList = let internal snd3 (_, a, _) = a let internal thd3 (_, _, a) = a - let unzip (list:FlatList<'a*'b>) = + let unzip list = let left = builderWithLengthOf list let right = builderWithLengthOf list for item in list do @@ -519,7 +559,7 @@ module FlatList = right.Add <| snd item left, right - let unzip3 (list:FlatList<'a*'b*'c>) = + let unzip3 list = let left = builderWithLengthOf list let right = builderWithLengthOf list let middle = builderWithLengthOf list @@ -527,7 +567,7 @@ module FlatList = left.Add <| fst3 item middle.Add <| snd3 item right.Add <| thd3 item - left, right + left, middle, right let windowed windowSize (list:FlatList<_>) = check list @@ -614,11 +654,18 @@ module FlatList = let max (list:FlatList<'a> when 'a : comparison) = check list; reduce max list let min (list:FlatList<'a> when 'a : comparison) = check list; reduce min list - let sortBy projection (list:FlatList<'a>) = list |> map projection |> sort + let internal flip f a b = f b a + let internal uncurry f (a, b) = f a b + + let sortBy projection = map projection >> sort let sortInPlaceBy = sortBy let sortInPlaceWith = sortWith let sortInPlace = sort + let sortDescending (list:FlatList<'a>) = sortWith (flip LanguagePrimitives.GenericComparison) list + let sortByDescending projection = map projection >> sortDescending + let compareWith comparer (left:FlatList<'a>) (right:FlatList<'b>) = zip left right |> skipWhile ((uncurry comparer) >> ((=) 0)) |> head |> (uncurry comparer) + ////////// module ImmutableArray = FlatList From 515f913e61fd804649a0eb554f7f29eb7ccf2b8b Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Wed, 19 May 2021 17:02:02 +0300 Subject: [PATCH 06/19] flat list - exactlyOne + try --- src/FSharp.Collections.Immutable/flat-list.fs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 198b94a..921630a 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -665,7 +665,16 @@ module FlatList = let sortByDescending projection = map projection >> sortDescending let compareWith comparer (left:FlatList<'a>) (right:FlatList<'b>) = zip left right |> skipWhile ((uncurry comparer) >> ((=) 0)) |> head |> (uncurry comparer) + + let tryExactlyOne (list:FlatList<_>) = + checkEmpty list + if length list > 1 then None else Some list.[0] + let exactlyOne list = + match tryExactlyOne list with + | None -> invalidArg (nameof list) "List contains more than one argument" + | Some a -> a + ////////// module ImmutableArray = FlatList From 82dbf1d7f138e4b5589093f02593a21b4e172d48 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Thu, 20 May 2021 07:54:21 +0300 Subject: [PATCH 07/19] flat-list - post-review fixes for first half --- src/FSharp.Collections.Immutable/flat-list.fs | 177 +++++------------- 1 file changed, 42 insertions(+), 135 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 921630a..356d00d 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -17,6 +17,7 @@ module FlatList = if list.IsDefault then invalidArg argName "Uninstantiated ImmutableArray/FlatList" let inline internal check (list : FlatList<'T>) = checkNotDefault (nameof list) list let inline internal checkEmpty (list : FlatList<_>) = check list; if list.Length = 0 then invalidArg (nameof list) "Source is empty" else () + let inline internal raiseOrReturn list = check list; list ////////// Creating ////////// @@ -204,17 +205,17 @@ module FlatList = for i = 0 to len - 1 do f.Invoke(list1.[i], list2.[i]) - let distinct (list: FlatList<'T>) = - let builder: FlatList<'T>.Builder = builderWith <| length list - let set = System.Collections.Generic.HashSet<'T>(HashIdentity.Structural) + let distinct (list: FlatList<'T>) = list |> System.Collections.Generic.HashSet |> ofSeq + + let distinctBy projection (list:FlatList<'a>) = + let builder = builderWithLengthOf list + let set = System.Collections.Generic.HashSet<'key>(HashIdentity.Structural) for item in list do - if set.Add item then - Builder.add item builder - + if set.Add <| projection item then + builder.Add item + ofBuilder builder - - let distinctBy projection (list:FlatList<'a>) = distinct list |> map projection let map2 mapping list1 list2 = checkNotDefault (nameof list1) list1 @@ -405,13 +406,7 @@ module FlatList = if predicate list.[i] then Some list.[i] else loop (i+1) loop <| length list - 1 - let findIndex predicate list = - check list - let len = length list - let rec loop i = - if i = len then indexNotFound() else - if predicate list.[i] then i else loop (i + 1) - loop 0 + let findIndex predicate = raiseOrReturn >> Seq.findIndex predicate let findIndexBack predicate list = check list @@ -420,13 +415,7 @@ module FlatList = if predicate list.[i] then i else loop (i - 1) loop <| length list - 1 - let tryFindIndex predicate list = - check list - let len = length list - let rec loop i = - if i = len then None else - if predicate list.[i] then Some i else loop (i + 1) - loop <| 0 + let tryFindIndex predicate = raiseOrReturn >> Seq.tryFindIndex predicate let tryFindIndexBack predicate list = check list @@ -435,117 +424,50 @@ module FlatList = if predicate list.[i] then Some i else loop (i - 1) loop <| length list - 1 - let fold folder (state: 'state) (list:FlatList<'a>) = - check list - let mutable result = state - for item in list do - result <- folder result item - result + let fold folder (state: 'state) = raiseOrReturn >> Seq.fold folder state - let scan folder (state: 'state) (list:FlatList<'a>) = - check list - let mutable s = state - let result = builderWithLengthOf list - result.Add s - for item in list do - s <- folder s item - result.Add s - result + let scan folder (state: 'state) = raiseOrReturn >> Seq.scan folder state >> ofSeq let fold2 folder (state: 'state) (left:FlatList<'a>) (right:FlatList<'b>) = - check left - let mutable result = state - let len = length left |> max (length right) - for i = 0 to len - 1 do - result <- folder result left.[i] right.[i] - result + check left; check right + Seq.fold2 folder state left right let foldBack2 folder (left:FlatList<'a>) (right:FlatList<'b>) (state:'state) = - check left - let mutable result = state - let leftLen = length left - let rightLen = length right - let len = max leftLen rightLen - for i = 0 to len - 1 do - result <- folder result left.[leftLen - i] right.[rightLen - i] - result + check left; check right + Seq.foldBack2 folder left right state let foldBack folder (list:FlatList<'a>) (state: 'state) = check list - let mutable result = state - for i = length list - 1 downto 0 do - result <- folder result list.[i] - result + Seq.foldBack folder list state - let scanBack folder (list:FlatList<'a>) (state: 'state) = + let scanBack folder (list:FlatList<'a>) (state:'state) = check list - let mutable s = state - let result = builderWithLengthOf list - result.Add s - for i = length list - 1 downto 0 do - s <- folder s list.[i] - result.Add s - result + Seq.scanBack folder list state |> ofSeq let unfold (generator: 'state -> ('a * 'state) option) state = - let builder = FlatListFactory.CreateBuilder() - let mutable s = state - let mutable step = generator s - while step.IsSome do - s <- snd step.Value - fst step.Value |> builder.Add - step <- generator s - ofBuilder builder + Seq.unfold generator state |> ofSeq - let reduce reduction (list:FlatList<'a>) = - checkEmpty list - let mutable result = list.[0] - for i = 1 to length list - 1 do - result <- reduction result list.[i] - result + let reduce reduction = raiseOrReturn >> Seq.reduce reduction - let reduceBack reduction (list:FlatList<'a>) = - checkEmpty list - let mutable result = list.[list.Length - 1] - for i = length list - 2 downto 0 do - result <- reduction result list.[i] - result + let reduceBack reduction = raiseOrReturn >> Seq.reduceBack reduction let mapFold mapping (state:'State) (list:FlatList<'T>) = check list - let builder = builderWithLengthOf list - let mutable outState = state - for item in list do - let item, newState = mapping outState item - builder.Add item - outState <- newState - ofBuilder builder, outState + let (items, s) = Seq.mapFold mapping state list + ofSeq items, s let mapFoldBack mapping (list:FlatList<'T>) (state:'State) = check list - let builder = builderWithLengthOf list - let mutable outState = state - for i = length list - 1 downto 0 do - let item, newState = mapping outState list.[i] - builder.Add item - outState <- newState - ofBuilder builder, outState + let (i, s) = Seq.mapFoldBack mapping list state + ofSeq i, s let zip (left:FlatList<_>) (right:FlatList<_>) = check left; check right - let len = max (length left) (length right) - let builder = builderWith len - for i = 0 to len do - builder.Add (left.[i], right.[i]) - ofBuilder builder + Seq.zip left right |> ofSeq let zip3 (left:FlatList<_>) (middle:FlatList<_>) (right:FlatList<_>) = check left; check middle; check right - let len = length middle |> max (length left) |> max (length right) - let builder = builderWith len - for i = 0 to len do - builder.Add (left.[i], middle.[i], right.[i]) - ofBuilder builder + Seq.zip3 left middle right |> ofSeq let internal fst3 (a, _, _) = a let internal snd3 (_, a, _) = a @@ -569,11 +491,7 @@ module FlatList = right.Add <| thd3 item left, middle, right - let windowed windowSize (list:FlatList<_>) = - check list - raise (new System.NotImplementedException()) - - // TODO: windowed + let windowed windowSize = raiseOrReturn >> Seq.windowed windowSize >> Seq.map ofSeq >> ofSeq ////////// Based on other operations ////////// @@ -630,29 +548,23 @@ module FlatList = moveFromBuilder builder let inline sum ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = - check list - reduce (+) list + list |> raiseOrReturn |> reduce (+) let inline sumBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = - check list - list |> map projection |> reduce (+) + list |> raiseOrReturn |> map projection |> reduce (+) + + let internal over f g h x = f (g x) (h x) let inline average ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = - check list - let len = length list - let sum = sum list - LanguagePrimitives.DivideByInt sum len + list |> raiseOrReturn |> over LanguagePrimitives.DivideByInt sum length let inline averageBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = - check list - let len = length list - let sum = list |> map projection |> sum - LanguagePrimitives.DivideByInt sum len + list |> raiseOrReturn |> over LanguagePrimitives.DivideByInt (map projection >> sum) length - let maxBy projection (list:FlatList<'a> when 'a : comparison) = check list; list |> map projection |> reduce max - let minBy projection (list:FlatList<'a> when 'a : comparison) = check list; list |> map projection |> reduce min - let max (list:FlatList<'a> when 'a : comparison) = check list; reduce max list - let min (list:FlatList<'a> when 'a : comparison) = check list; reduce min list + let maxBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> map projection |> reduce max + let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> map projection |> reduce min + let max (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce max + let min (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce min let internal flip f a b = f b a let internal uncurry f (a, b) = f a b @@ -666,14 +578,9 @@ module FlatList = let compareWith comparer (left:FlatList<'a>) (right:FlatList<'b>) = zip left right |> skipWhile ((uncurry comparer) >> ((=) 0)) |> head |> (uncurry comparer) - let tryExactlyOne (list:FlatList<_>) = - checkEmpty list - if length list > 1 then None else Some list.[0] + let tryExactlyOne = Seq.tryExactlyOne - let exactlyOne list = - match tryExactlyOne list with - | None -> invalidArg (nameof list) "List contains more than one argument" - | Some a -> a + let exactlyOne = Seq.exactlyOne ////////// From b5dc6df1e58e4725349b2adb4fc15531c788ebf7 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Thu, 20 May 2021 09:30:32 +0300 Subject: [PATCH 08/19] flat list - fix sorting (and helpers) --- src/FSharp.Collections.Immutable/flat-list.fs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 356d00d..6cbcd05 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -553,13 +553,14 @@ module FlatList = let inline sumBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> map projection |> reduce (+) - let internal over f g h x = f (g x) (h x) + let inline internal applyOverFuncs f g h x = f (g x) (h x) + let inline internal applyOverArgs f g x y = f (g x) (g y) let inline average ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = - list |> raiseOrReturn |> over LanguagePrimitives.DivideByInt sum length + list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt sum length let inline averageBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = - list |> raiseOrReturn |> over LanguagePrimitives.DivideByInt (map projection >> sum) length + list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt (map projection >> sum) length let maxBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> map projection |> reduce max let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> map projection |> reduce min @@ -569,12 +570,12 @@ module FlatList = let internal flip f a b = f b a let internal uncurry f (a, b) = f a b - let sortBy projection = map projection >> sort + let sortBy projection = sortWith (applyOverArgs LanguagePrimitives.GenericComparison projection) let sortInPlaceBy = sortBy let sortInPlaceWith = sortWith let sortInPlace = sort let sortDescending (list:FlatList<'a>) = sortWith (flip LanguagePrimitives.GenericComparison) list - let sortByDescending projection = map projection >> sortDescending + let sortByDescending projection = sortWith (flip (applyOverArgs LanguagePrimitives.GenericComparison projection)) let compareWith comparer (left:FlatList<'a>) (right:FlatList<'b>) = zip left right |> skipWhile ((uncurry comparer) >> ((=) 0)) |> head |> (uncurry comparer) From 3b9c912e360a1fdca3e528c680b1ebf8850418da Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Thu, 20 May 2021 09:38:43 +0300 Subject: [PATCH 09/19] general: vscode build task, move common funcs --- .vscode/tasks.json | 27 ++++++ .../FSharp.Collections.Immutable.fsproj | 86 +++++++++---------- src/FSharp.Collections.Immutable/flat-list.fs | 10 --- .../functional-utils.fs | 17 ++++ 4 files changed, 85 insertions(+), 55 deletions(-) create mode 100644 .vscode/tasks.json create mode 100644 src/FSharp.Collections.Immutable/functional-utils.fs diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..b26cc9a --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,27 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "shell", + "args": [ + "build", + // Ask dotnet build to generate full paths for file names. + "/property:GenerateFullPaths=true", + // Do not generate summary otherwise it leads to duplicate errors in Problems panel + "/consoleloggerparameters:NoSummary" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj index 2b3fbfb..a9177f1 100644 --- a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj +++ b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj @@ -1,45 +1,41 @@ - - - - netstandard2.0 - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - F# bindings for System.Collections.Immutable - Copyright © XperiAndri 2016 - FSharp.Collections.Immutable - XperiAndri - FSharp.Collections.Immutable - 2.0.0 - XperiAndri;EventHelix;vilinski;anthony-mi;dim-37 - true - FSharp.Collections.Immutable - System;Immutable;Collections;FSharp;F# - git - embedded - https://github.com/fsprojects/FSharp.Collections.Immutable/ - https://github.com/fsprojects/FSharp.Collections.Immutable/ - true - true - - - - - - - - - - - - - - - - true - - - - - - - - + + + netstandard2.0 + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + F# bindings for System.Collections.Immutable + Copyright © XperiAndri 2016 + FSharp.Collections.Immutable + XperiAndri + FSharp.Collections.Immutable + 2.0.0 + XperiAndri;EventHelix;vilinski;anthony-mi;dim-37 + true + FSharp.Collections.Immutable + System;Immutable;Collections;FSharp;F# + git + embedded + https://github.com/fsprojects/FSharp.Collections.Immutable/ + https://github.com/fsprojects/FSharp.Collections.Immutable/ + true + true + + + + + + + + + + + + + + + true + + + + + + \ No newline at end of file diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 6cbcd05..4042ebe 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -469,10 +469,6 @@ module FlatList = check left; check middle; check right Seq.zip3 left middle right |> ofSeq - let internal fst3 (a, _, _) = a - let internal snd3 (_, a, _) = a - let internal thd3 (_, _, a) = a - let unzip list = let left = builderWithLengthOf list let right = builderWithLengthOf list @@ -553,9 +549,6 @@ module FlatList = let inline sumBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> map projection |> reduce (+) - let inline internal applyOverFuncs f g h x = f (g x) (h x) - let inline internal applyOverArgs f g x y = f (g x) (g y) - let inline average ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt sum length @@ -567,9 +560,6 @@ module FlatList = let max (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce max let min (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce min - let internal flip f a b = f b a - let internal uncurry f (a, b) = f a b - let sortBy projection = sortWith (applyOverArgs LanguagePrimitives.GenericComparison projection) let sortInPlaceBy = sortBy let sortInPlaceWith = sortWith diff --git a/src/FSharp.Collections.Immutable/functional-utils.fs b/src/FSharp.Collections.Immutable/functional-utils.fs new file mode 100644 index 0000000..ac6f0d1 --- /dev/null +++ b/src/FSharp.Collections.Immutable/functional-utils.fs @@ -0,0 +1,17 @@ +#if INTERACTIVE +namespace global +#else +namespace FSharp.Collections.Immutable +#endif + +[] +module internal FunctionalUtils = + let inline flip f a b = f b a + let inline uncurry f (a, b) = f a b + + let inline applyOverFuncs f g h x = f (g x) (h x) + let inline applyOverArgs f g x y = f (g x) (g y) + + let inline fst3 (a, _, _) = a + let inline snd3 (_, a, _) = a + let inline thd3 (_, _, a) = a \ No newline at end of file From 3cc77b14fc865656ec5a0f31b80d0a45c8b86c5e Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Thu, 20 May 2021 13:15:08 +0300 Subject: [PATCH 10/19] flat list - remove sortInPlace* --- src/FSharp.Collections.Immutable/flat-list.fs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 4042ebe..7ecb3bb 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -561,9 +561,6 @@ module FlatList = let min (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce min let sortBy projection = sortWith (applyOverArgs LanguagePrimitives.GenericComparison projection) - let sortInPlaceBy = sortBy - let sortInPlaceWith = sortWith - let sortInPlace = sort let sortDescending (list:FlatList<'a>) = sortWith (flip LanguagePrimitives.GenericComparison) list let sortByDescending projection = sortWith (flip (applyOverArgs LanguagePrimitives.GenericComparison projection)) From b200e5caf6ef4cdd897ead02edfc10fb1193f6fb Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Thu, 20 May 2021 13:35:37 +0300 Subject: [PATCH 11/19] flat list - all APIs ported --- src/FSharp.Collections.Immutable/flat-list.fs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 7ecb3bb..4b3019c 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -149,6 +149,8 @@ module FlatList = builder.Add <| initializer i moveFromBuilder builder + let zeroCreate<'a> count = init count (fun _ -> Unchecked.defaultof<'a>) + let rec private concatAddLengths (arrs: FlatList>) i acc = if i >= length arrs then acc else concatAddLengths arrs (i+1) (acc + arrs.[i].Length) @@ -489,6 +491,11 @@ module FlatList = let windowed windowSize = raiseOrReturn >> Seq.windowed windowSize >> Seq.map ofSeq >> ofSeq + let fill target targetIndex count value = + indexed target + |> map (fun (i, a) -> if targetIndex <= i && i < targetIndex + count then value else a) + |> ofSeq + ////////// Based on other operations ////////// let take count list = removeRange count (length list - count) list @@ -567,9 +574,17 @@ module FlatList = let compareWith comparer (left:FlatList<'a>) (right:FlatList<'b>) = zip left right |> skipWhile ((uncurry comparer) >> ((=) 0)) |> head |> (uncurry comparer) let tryExactlyOne = Seq.tryExactlyOne - let exactlyOne = Seq.exactlyOne + let rev = Seq.rev >> ofSeq + let transpose = Seq.transpose >> Seq.map ofSeq >> ofSeq + let permute indexMap = Seq.permute indexMap >> ofSeq + let pairwise = Seq.pairwise >> ofSeq + let except itemsToExclude = Seq.except itemsToExclude >> ofSeq + let splitInto count = Seq.splitInto count >> Seq.map ofSeq >> ofSeq + let chunkBySize chunkSize = Seq.chunkBySize chunkSize >> Seq.map ofSeq >> ofSeq + let allPairs left = Seq.allPairs left >> ofSeq + ////////// module ImmutableArray = FlatList From bbf1366c69259ed35a02c94eb7660aab5cd8f889 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Thu, 20 May 2021 14:41:59 +0300 Subject: [PATCH 12/19] flat list - post-review fixes --- src/FSharp.Collections.Immutable/flat-list.fs | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 4b3019c..4b74221 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -149,8 +149,6 @@ module FlatList = builder.Add <| initializer i moveFromBuilder builder - let zeroCreate<'a> count = init count (fun _ -> Unchecked.defaultof<'a>) - let rec private concatAddLengths (arrs: FlatList>) i acc = if i >= length arrs then acc else concatAddLengths arrs (i+1) (acc + arrs.[i].Length) @@ -209,15 +207,7 @@ module FlatList = let distinct (list: FlatList<'T>) = list |> System.Collections.Generic.HashSet |> ofSeq - let distinctBy projection (list:FlatList<'a>) = - let builder = builderWithLengthOf list - let set = System.Collections.Generic.HashSet<'key>(HashIdentity.Structural) - - for item in list do - if set.Add <| projection item then - builder.Add item - - ofBuilder builder + let distinctBy projection (list:FlatList<'a>) = Seq.distinctBy projection >> ofSeq let map2 mapping list1 list2 = checkNotDefault (nameof list1) list1 @@ -477,7 +467,7 @@ module FlatList = for item in list do left.Add <| fst item right.Add <| snd item - left, right + ofBuilder left, ofBuilder right let unzip3 list = let left = builderWithLengthOf list @@ -487,7 +477,7 @@ module FlatList = left.Add <| fst3 item middle.Add <| snd3 item right.Add <| thd3 item - left, middle, right + ofBuilder left, ofBuilder middle, ofBuilder right let windowed windowSize = raiseOrReturn >> Seq.windowed windowSize >> Seq.map ofSeq >> ofSeq @@ -562,8 +552,8 @@ module FlatList = let inline averageBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt (map projection >> sum) length - let maxBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> map projection |> reduce max - let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> map projection |> reduce min + let maxBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> Seq.map projection |> Seq.reduce max + let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> Seq.map projection |> Seq.reduce min let max (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce max let min (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce min @@ -571,10 +561,10 @@ module FlatList = let sortDescending (list:FlatList<'a>) = sortWith (flip LanguagePrimitives.GenericComparison) list let sortByDescending projection = sortWith (flip (applyOverArgs LanguagePrimitives.GenericComparison projection)) - let compareWith comparer (left:FlatList<'a>) (right:FlatList<'b>) = zip left right |> skipWhile ((uncurry comparer) >> ((=) 0)) |> head |> (uncurry comparer) + let compareWith comparer (left:FlatList<'a>) (right:FlatList<'b>) = zip left right |> Seq.skipWhile ((uncurry comparer) >> ((=) 0)) |> Seq.head |> (uncurry comparer) - let tryExactlyOne = Seq.tryExactlyOne - let exactlyOne = Seq.exactlyOne + let tryExactlyOne (list:FlatList<_>) = Seq.tryExactlyOne list + let exactlyOne (list:FlatList<_>) = Seq.exactlyOne list let rev = Seq.rev >> ofSeq let transpose = Seq.transpose >> Seq.map ofSeq >> ofSeq From 0ee37d53683ee18029c5666e81ac4ce951ef00ba Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Thu, 20 May 2021 15:52:32 +0300 Subject: [PATCH 13/19] flat list - update signatures: force main arg as FlatList --- src/FSharp.Collections.Immutable/flat-list.fs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 4b74221..2363937 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -550,7 +550,7 @@ module FlatList = list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt sum length let inline averageBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = - list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt (map projection >> sum) length + list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt ((map projection) >> sum) length let maxBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> Seq.map projection |> Seq.reduce max let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> Seq.map projection |> Seq.reduce min @@ -566,14 +566,14 @@ module FlatList = let tryExactlyOne (list:FlatList<_>) = Seq.tryExactlyOne list let exactlyOne (list:FlatList<_>) = Seq.exactlyOne list - let rev = Seq.rev >> ofSeq - let transpose = Seq.transpose >> Seq.map ofSeq >> ofSeq - let permute indexMap = Seq.permute indexMap >> ofSeq - let pairwise = Seq.pairwise >> ofSeq - let except itemsToExclude = Seq.except itemsToExclude >> ofSeq - let splitInto count = Seq.splitInto count >> Seq.map ofSeq >> ofSeq - let chunkBySize chunkSize = Seq.chunkBySize chunkSize >> Seq.map ofSeq >> ofSeq - let allPairs left = Seq.allPairs left >> ofSeq + let rev = raiseOrReturn >> Seq.rev >> ofSeq + let transpose = raiseOrReturn >> Seq.transpose >> Seq.map ofSeq >> ofSeq + let permute indexMap = raiseOrReturn >> Seq.permute indexMap >> ofSeq + let pairwise = raiseOrReturn >> Seq.pairwise >> ofSeq + let except itemsToExclude = raiseOrReturn >> Seq.except itemsToExclude >> ofSeq + let splitInto count = raiseOrReturn >> Seq.splitInto count >> Seq.map ofSeq >> ofSeq + let chunkBySize chunkSize = raiseOrReturn >> Seq.chunkBySize chunkSize >> Seq.map ofSeq >> ofSeq + let allPairs (left:FlatList<'a>) (right:FlatList<'b>) = Seq.allPairs (raiseOrReturn left) (raiseOrReturn right) |> ofSeq ////////// From 697c5f85a0347b4c6487181a9aaaaf5a9147e400 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Fri, 21 May 2021 09:30:07 +0300 Subject: [PATCH 14/19] flat-list - changes - remove excessive `get` - add initialization with value (and use in `create`/`replicate`) - use `Seq` in majority of functions - simplify `fill` - fix signatures --- src/FSharp.Collections.Immutable/flat-list.fs | 234 ++++-------------- 1 file changed, 43 insertions(+), 191 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 2363937..73ef59a 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -136,8 +136,6 @@ module FlatList = let sortWith comparer list = sortWithComparer (ComparisonIdentity.FromFunction comparer) list let sort list = check list; list.Sort() - let get (list:FlatList<_>) index = list.[index] - ////////// Loop-based ////////// let inline private builderWithLengthOf list = builderWith <| length list @@ -149,22 +147,20 @@ module FlatList = builder.Add <| initializer i moveFromBuilder builder + let initWithValue count value = + if count < 0 then invalidArg(nameof count) ErrorStrings.InputMustBeNonNegative + let builder = builderWith count + for i = 0 to count - 1 do + builder.Add value + ofBuilder builder + let rec private concatAddLengths (arrs: FlatList>) i acc = if i >= length arrs then acc else concatAddLengths arrs (i+1) (acc + arrs.[i].Length) - let concat (arrs : FlatList>) = // consider generalizing - let result: FlatList<'T>.Builder = builderWith <| concatAddLengths arrs 0 0 - for i = 0 to length arrs - 1 do - result.AddRange(arrs.[i]: FlatList<'T>) - moveFromBuilder result + let concat (seqs:'a seq seq) = seqs |> Seq.concat |> ofSeq - let inline map mapping list = - check list - let builder = builderWithLengthOf list - for i = 0 to length list - 1 do - builder.Add(mapping list.[i]) - moveFromBuilder builder + let inline map mapping = raiseOrReturn >> Seq.map mapping >> ofSeq let countBy projection list = check list @@ -191,10 +187,7 @@ module FlatList = builder.Add(i, list.[i]) moveFromBuilder builder - let inline iter action list = - check list - for i = 0 to length list - 1 do - action list.[i] + let inline iter action = raiseOrReturn >> Seq.iter action let iter2 action list1 list2 = checkNotDefault (nameof list1) list1 @@ -212,157 +205,51 @@ module FlatList = let map2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(mapping) - let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - let res = builderWith len1 - for i = 0 to len1 - 1 do - res.Add <| f.Invoke(list1.[i], list2.[i]) - moveFromBuilder res + Seq.map2 mapping list1 list2 |> ofSeq let map3 mapping list1 list2 list3 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 checkNotDefault (nameof list3) list3 - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(mapping) - let len1 = list1.Length - if not (len1 = list2.Length) - then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - if not (len1 = list3.Length) - then invalidArg (nameof list3) ErrorStrings.ListsHaveDifferentLengths - - let res = builderWith len1 - for i = 0 to len1 - 1 do - res.Add <| f.Invoke(list1.[i], list2.[i], list3.[i]) - moveFromBuilder res + Seq.map3 mapping list1 list2 list3 |> ofSeq + let mapi2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(mapping) - let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - let res = builderWith len1 - for i = 0 to len1 - 1 do - res.Add <| f.Invoke(i,list1.[i], list2.[i]) - moveFromBuilder res + Seq.mapi2 mapping list1 list2 |> ofSeq - let iteri action list = - check list - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(action) - let len = list.Length - for i = 0 to len - 1 do - f.Invoke(i, list.[i]) + let iteri action = raiseOrReturn >> Seq.iteri action let iteri2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(action) - let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - for i = 0 to len1 - 1 do - f.Invoke(i,list1.[i], list2.[i]) + Seq.iteri2 action list1 list2 - let mapi mapping list = - check list - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(mapping) - let len = list.Length - let res = builderWithLengthOf list - for i = 0 to len - 1 do - res.Add <| f.Invoke(i,list.[i]) - moveFromBuilder res + let mapi mapping = raiseOrReturn >> Seq.mapi mapping >> ofSeq - let exists predicate list = - check list - let len = list.Length - let rec loop i = i < len && (predicate list.[i] || loop (i+1)) - loop 0 + let exists predicate = raiseOrReturn >> Seq.exists predicate - let inline contains e list = - check list - let mutable state = false - let mutable i = 0 - while (not state && i < list.Length) do - state <- e = list.[i] - i <- i + 1 - state + let inline contains e = raiseOrReturn >> Seq.contains e let exists2 predicate list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(predicate) - let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - let rec loop i = i < len1 && (f.Invoke(list1.[i], list2.[i]) || loop (i+1)) - loop 0 + Seq.exists2 predicate list1 list2 - let forall predicate list = - check list - let len = list.Length - let rec loop i = i >= len || (predicate list.[i] && loop (i+1)) - loop 0 + let forall predicate = raiseOrReturn >> Seq.forall predicate let forall2 predicate list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(predicate) - let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - let rec loop i = i >= len1 || (f.Invoke(list1.[i], list2.[i]) && loop (i+1)) - loop 0 + Seq.forall2 predicate list1 list2 - let groupBy projection list = - check list - let dict = new System.Collections.Generic.Dictionary<'Key,ResizeArray<'T>>(HashIdentity.Structural) + let groupBy projection = raiseOrReturn >> Seq.groupBy projection >> Seq.map (fun (k, i) -> k, ofSeq i) >> ofSeq - // Build the groupings - for i = 0 to (list.Length - 1) do - let v = list.[i] - let key = projection v - let ok, prev = dict.TryGetValue(key) - if ok then - prev.Add(v) - else - let prev = new ResizeArray<'T>(1) - dict.[key] <- prev - prev.Add(v) - - // Return the list-of-lists. - let result = builderWith dict.Count - let mutable i = 0 - for group in dict do - result.Add(group.Key, ofSeq group.Value) - i <- i + 1 + let pick chooser = raiseOrReturn >> Seq.pick chooser - moveFromBuilder result + let tryPick chooser = raiseOrReturn >> Seq.tryPick chooser - let pick chooser list = - check list - let rec loop i = - if i >= list.Length then - indexNotFound() - else - match chooser list.[i] with - | None -> loop(i+1) - | Some res -> res - loop 0 - - let tryPick chooser list = - check list - let rec loop i = - if i >= list.Length then None else - match chooser list.[i] with - | None -> loop(i+1) - | res -> res - loop 0 - - let choose chooser list = - check list - let res = builderWith list.Length - for i = 0 to list.Length - 1 do - match chooser list.[i] with - | None -> () - | Some b -> res.Add(b) - ofBuilder res + let choose chooser = raiseOrReturn >> Seq.choose chooser >> ofSeq let partition predicate list = check list @@ -373,48 +260,14 @@ module FlatList = if predicate x then res1.Add(x) else res2.Add(x) ofBuilder res1, ofBuilder res2 - let find predicate list = - check list - let rec loop i = - if i >= list.Length then indexNotFound() else - if predicate list.[i] then list.[i] else loop (i+1) - loop 0 - let tryFind predicate list = - check list - let rec loop i = - if i >= list.Length then None else - if predicate list.[i] then Some list.[i] else loop (i+1) - loop 0 - let findBack predicate list = - check list - let rec loop i = - if i < 0 then indexNotFound() else - if predicate list.[i] then list.[i] else loop (i - 1) - loop <| length list - 1 - let tryFindBack predicate list = - check list - let rec loop i = - if i < 0 then None else - if predicate list.[i] then Some list.[i] else loop (i+1) - loop <| length list - 1 - + let find predicate = raiseOrReturn >> Seq.find predicate + let tryFind predicate = raiseOrReturn >> Seq.tryFind predicate + let findBack predicate = raiseOrReturn >> Seq.findBack predicate + let tryFindBack predicate = raiseOrReturn >> Seq.tryFindBack predicate let findIndex predicate = raiseOrReturn >> Seq.findIndex predicate - - let findIndexBack predicate list = - check list - let rec loop i = - if i < 0 then indexNotFound() else - if predicate list.[i] then i else loop (i - 1) - loop <| length list - 1 - + let findIndexBack predicate = raiseOrReturn >> Seq.findIndexBack predicate let tryFindIndex predicate = raiseOrReturn >> Seq.tryFindIndex predicate - - let tryFindIndexBack predicate list = - check list - let rec loop i = - if i < 0 then None else - if predicate list.[i] then Some i else loop (i - 1) - loop <| length list - 1 + let tryFindIndexBack predicate = raiseOrReturn >> Seq.tryFindIndexBack predicate let fold folder (state: 'state) = raiseOrReturn >> Seq.fold folder state @@ -482,8 +335,7 @@ module FlatList = let windowed windowSize = raiseOrReturn >> Seq.windowed windowSize >> Seq.map ofSeq >> ofSeq let fill target targetIndex count value = - indexed target - |> map (fun (i, a) -> if targetIndex <= i && i < targetIndex + count then value else a) + mapi (fun i a -> if targetIndex <= i && i < targetIndex + count then value else a) target |> ofSeq ////////// Based on other operations ////////// @@ -520,13 +372,13 @@ module FlatList = let tryLast list = tryItem (length list - 1) list - let tail list = removeRange 1 (length list - 1) list + let tail list = skip 1 list let tryTail list = if isEmpty list then None else Some <| tail list - let create count item = init count <| fun _ -> item // optimize + let create = initWithValue - let replicate count item = create item count + let replicate item = item |> flip initWithValue let collect mapping list = concat <| map mapping list @@ -566,13 +418,13 @@ module FlatList = let tryExactlyOne (list:FlatList<_>) = Seq.tryExactlyOne list let exactlyOne (list:FlatList<_>) = Seq.exactlyOne list - let rev = raiseOrReturn >> Seq.rev >> ofSeq - let transpose = raiseOrReturn >> Seq.transpose >> Seq.map ofSeq >> ofSeq - let permute indexMap = raiseOrReturn >> Seq.permute indexMap >> ofSeq - let pairwise = raiseOrReturn >> Seq.pairwise >> ofSeq - let except itemsToExclude = raiseOrReturn >> Seq.except itemsToExclude >> ofSeq - let splitInto count = raiseOrReturn >> Seq.splitInto count >> Seq.map ofSeq >> ofSeq - let chunkBySize chunkSize = raiseOrReturn >> Seq.chunkBySize chunkSize >> Seq.map ofSeq >> ofSeq + let rev (list:FlatList<_>) = list |> raiseOrReturn |> Seq.rev |> ofSeq + let transpose (list:FlatList<_>) = list |> raiseOrReturn |> Seq.transpose |> Seq.map ofSeq |> ofSeq + let permute indexMap (list:FlatList<_>) = list |> raiseOrReturn |> Seq.permute indexMap |> ofSeq + let pairwise (list:FlatList<_>) = list |> raiseOrReturn |> Seq.pairwise |> ofSeq + let except itemsToExclude (list:FlatList<_>) = list |> raiseOrReturn |> Seq.except itemsToExclude |> ofSeq + let splitInto count (list:FlatList<_>) = list |> raiseOrReturn |> Seq.splitInto count |> Seq.map ofSeq |> ofSeq + let chunkBySize chunkSize (list:FlatList<_>) = list |> raiseOrReturn |> Seq.chunkBySize chunkSize |> Seq.map ofSeq |> ofSeq let allPairs (left:FlatList<'a>) (right:FlatList<'b>) = Seq.allPairs (raiseOrReturn left) (raiseOrReturn right) |> ofSeq ////////// From 8af69b9e496d35d11a567bc9c31fa8deb9bdf6bf Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Fri, 21 May 2021 09:37:19 +0300 Subject: [PATCH 15/19] flat list - fix minor issues - change `countBy`, `indexed`, `iter2` to use `Seq` - fix distinctBy (remove excessive arg + use `raiseOrReturn`) --- src/FSharp.Collections.Immutable/flat-list.fs | 63 ++++++------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 73ef59a..658f2ea 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -162,45 +162,20 @@ module FlatList = let inline map mapping = raiseOrReturn >> Seq.map mapping >> ofSeq - let countBy projection list = - check list - // need struct box optimization - let dict = new System.Collections.Generic.Dictionary<'Key, int>(HashIdentity.Structural) - - // Build the groupings - for v in list do - let key = projection v - let mutable prev = Unchecked.defaultof<_> - if dict.TryGetValue(key, &prev) then dict.[key] <- prev + 1 else dict.[key] <- 1 - - let res = builderWith dict.Count - let mutable i = 0 - for group in dict do - res.Add(group.Key, group.Value) - i <- i + 1 - moveFromBuilder res - - let indexed list = - check list - let builder = builderWithLengthOf list - for i = 0 to length list - 1 do - builder.Add(i, list.[i]) - moveFromBuilder builder + let countBy projection = raiseOrReturn >> Seq.countBy projection >> ofSeq + + let indexed list = list |> raiseOrReturn |> Seq.indexed |> ofSeq let inline iter action = raiseOrReturn >> Seq.iter action let iter2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<'T,'U, unit>.Adapt(action) - let len = length list1 - if len <> length list2 then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - for i = 0 to len - 1 do - f.Invoke(list1.[i], list2.[i]) + Seq.iter2 action list1 list2 let distinct (list: FlatList<'T>) = list |> System.Collections.Generic.HashSet |> ofSeq - - let distinctBy projection (list:FlatList<'a>) = Seq.distinctBy projection >> ofSeq + + let distinctBy projection = raiseOrReturn >> Seq.distinctBy projection >> ofSeq let map2 mapping list1 list2 = checkNotDefault (nameof list1) list1 @@ -223,7 +198,7 @@ module FlatList = let iteri2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - Seq.iteri2 action list1 list2 + Seq.iteri2 action list1 list2 let mapi mapping = raiseOrReturn >> Seq.mapi mapping >> ofSeq @@ -268,32 +243,32 @@ module FlatList = let findIndexBack predicate = raiseOrReturn >> Seq.findIndexBack predicate let tryFindIndex predicate = raiseOrReturn >> Seq.tryFindIndex predicate let tryFindIndexBack predicate = raiseOrReturn >> Seq.tryFindIndexBack predicate - + let fold folder (state: 'state) = raiseOrReturn >> Seq.fold folder state - + let scan folder (state: 'state) = raiseOrReturn >> Seq.scan folder state >> ofSeq - + let fold2 folder (state: 'state) (left:FlatList<'a>) (right:FlatList<'b>) = check left; check right Seq.fold2 folder state left right - + let foldBack2 folder (left:FlatList<'a>) (right:FlatList<'b>) (state:'state) = check left; check right Seq.foldBack2 folder left right state - + let foldBack folder (list:FlatList<'a>) (state: 'state) = check list Seq.foldBack folder list state - + let scanBack folder (list:FlatList<'a>) (state:'state) = check list Seq.scanBack folder list state |> ofSeq let unfold (generator: 'state -> ('a * 'state) option) state = Seq.unfold generator state |> ofSeq - + let reduce reduction = raiseOrReturn >> Seq.reduce reduction - + let reduceBack reduction = raiseOrReturn >> Seq.reduceBack reduction let mapFold mapping (state:'State) (list:FlatList<'T>) = @@ -305,11 +280,11 @@ module FlatList = check list let (i, s) = Seq.mapFoldBack mapping list state ofSeq i, s - + let zip (left:FlatList<_>) (right:FlatList<_>) = check left; check right Seq.zip left right |> ofSeq - + let zip3 (left:FlatList<_>) (middle:FlatList<_>) (right:FlatList<_>) = check left; check middle; check right Seq.zip3 left middle right |> ofSeq @@ -392,10 +367,10 @@ module FlatList = f builder moveFromBuilder builder - let inline sum ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = + let inline sum ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> reduce (+) - let inline sumBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = + let inline sumBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> map projection |> reduce (+) let inline average ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = From 452bfb9aea46bf36be2a83a4cdfb514eaf4b5f79 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Fri, 21 May 2021 14:14:53 +0300 Subject: [PATCH 16/19] flat list - final post-review changes --- src/FSharp.Collections.Immutable/flat-list.fs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 658f2ea..502037a 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -148,7 +148,7 @@ module FlatList = moveFromBuilder builder let initWithValue count value = - if count < 0 then invalidArg(nameof count) ErrorStrings.InputMustBeNonNegative + if count < 0 then invalidArg (nameof count) ErrorStrings.InputMustBeNonNegative let builder = builderWith count for i = 0 to count - 1 do builder.Add value @@ -160,20 +160,20 @@ module FlatList = let concat (seqs:'a seq seq) = seqs |> Seq.concat |> ofSeq - let inline map mapping = raiseOrReturn >> Seq.map mapping >> ofSeq + let map mapping = raiseOrReturn >> Seq.map mapping >> ofSeq let countBy projection = raiseOrReturn >> Seq.countBy projection >> ofSeq let indexed list = list |> raiseOrReturn |> Seq.indexed |> ofSeq - let inline iter action = raiseOrReturn >> Seq.iter action + let iter action = raiseOrReturn >> Seq.iter action let iter2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.iter2 action list1 list2 - let distinct (list: FlatList<'T>) = list |> System.Collections.Generic.HashSet |> ofSeq + let distinct (list: FlatList<'T>) = list |> Seq.distinct |> ofSeq let distinctBy projection = raiseOrReturn >> Seq.distinctBy projection >> ofSeq @@ -204,7 +204,7 @@ module FlatList = let exists predicate = raiseOrReturn >> Seq.exists predicate - let inline contains e = raiseOrReturn >> Seq.contains e + let contains e = raiseOrReturn >> Seq.contains e let exists2 predicate list1 list2 = checkNotDefault (nameof list1) list1 From c020a360c0486bd87739685a68b1c74005edbc93 Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Tue, 8 Jun 2021 09:44:11 +0300 Subject: [PATCH 17/19] add compiled name annotations --- src/FSharp.Collections.Immutable/flat-list.fs | 176 +++++++++++++++++- 1 file changed, 172 insertions(+), 4 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 502037a..1c7c3cb 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -2,6 +2,9 @@ namespace global #else namespace FSharp.Collections.Immutable + +open FSharp.Collections.Immutable + #endif // The FlatList name comes from a similar construct seen in the official F# source code @@ -21,49 +24,70 @@ module FlatList = ////////// Creating ////////// + [] let inline empty<'T> : FlatList<_> = FlatListFactory.Create<'T>() + [] let inline singleton<'T> (item : 'T) : FlatList<'T> = FlatListFactory.Create<'T> (item) + [] let copy (list:FlatList<_>) = FlatListFactory.CreateRange list + [] let inline ofSeq source = FlatListFactory.CreateRange source + [] let inline ofArray (source : _ array) = FlatListFactory.CreateRange source + [] let inline ofList (source: _ list) = FlatListFactory.CreateRange source + [] let inline toSeq (flatList: FlatList<_>) = flatList :> seq<_> + [] let inline toArray (list : FlatList<_>) = check list; Seq.toArray list + [] let inline toList list = check list; Seq.toList list ////////// Building ////////// + [] let moveFromBuilder (builder : FlatList<_>.Builder) : FlatList<_> = checkNotNull (nameof builder) builder builder.MoveToImmutable() + [] let ofBuilder (builder : FlatList<_>.Builder) : FlatList<_> = checkNotNull (nameof builder) builder builder.ToImmutable() + [] let inline builder () : FlatList<'T>.Builder = FlatListFactory.CreateBuilder() + [] let inline builderWith capacity : FlatList<'T>.Builder = FlatListFactory.CreateBuilder(capacity) + [] let toBuilder list: FlatList<_>.Builder = check list; list.ToBuilder() module Builder = let inline private check (builder: FlatList<'T>.Builder) = checkNotNull (nameof builder) builder + [] let add item builder = check builder; builder.Add(item) let inline internal indexNotFound() = raise <| System.Collections.Generic.KeyNotFoundException() + [] let isEmpty (list: FlatList<_>) = list.IsEmpty + [] let isDefault (list: FlatList<_>) = list.IsDefault + [] let isDefaultOrEmpty (list: FlatList<_>) = list.IsDefaultOrEmpty ////////// IReadOnly* ////////// + [] let length list = check list; list.Length + [] let item index list = check list; list.[index] + [] let append list1 list2 : FlatList<'T> = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 @@ -72,74 +96,99 @@ module FlatList = /// Searches for the specified object and returns the zero-based index of the first occurrence within the range /// of elements in the list that starts at the specified index and /// contains the specified number of elements. + [] let indexRangeWith comparer index count item list = check list list.IndexOf(item, index, count, comparer) + [] let indexRange index count item list = indexRangeWith HashIdentity.Structural index count item list + [] let indexFromWith comparer index item list = indexRangeWith comparer index (length list - index) item + [] let indexFrom index item list = indexFromWith HashIdentity.Structural index item list + [] let indexWith comparer item list = indexFromWith comparer 0 item list + [] let index item list = indexWith HashIdentity.Structural item list /// Searches for the specified object and returns the zero-based index of the last occurrence within the /// range of elements in the list that contains the specified number /// of elements and ends at the specified index. + [] let lastIndexRangeWith comparer index count item list = check list list.LastIndexOf(item, index, count, comparer) + [] let lastIndexRange index count item list = lastIndexRangeWith HashIdentity.Structural index count item list + [] let lastIndexFromWith comparer index item list = lastIndexRangeWith comparer index (index + 1) item list + [] let lastIndexFrom index item list = lastIndexFromWith HashIdentity.Structural index item list + [] let lastIndexWith comparer item list = lastIndexFromWith comparer (length list - 1) item list + [] let lastIndex item list = lastIndexWith HashIdentity.Structural item list /// Removes the specified objects from the list with the given comparer. + [] let removeAllWith (comparer: System.Collections.Generic.IEqualityComparer<_>) items list: FlatList<_> = check list list.RemoveRange(items, comparer) /// Removes the specified objects from the list. + [] let removeAll items list = removeAllWith HashIdentity.Structural items list /// Removes all the elements that do not match the conditions defined by the specified predicate. + [] let filter predicate list: FlatList<_> = check list System.Predicate(not << predicate) |> list.RemoveAll /// Removes all the elements that do not match the conditions defined by the specified predicate. + [] let where predicate list = filter predicate list /// Removes a range of elements from the list. + [] let removeRange index (count: int) list: FlatList<_> = check list; list.RemoveRange(index, count) + [] let blit source sourceIndex (destination: 'T[]) destinationIndex count = checkNotDefault (nameof source) source try source.CopyTo(sourceIndex, destination, destinationIndex, count) with exn -> raise exn // throw same exception with the correct stack trace. Update exception code + [] let sortRangeWithComparer comparer index count list = check list list.Sort(index, count, comparer) + [] let sortRangeWith comparer index count list = sortRangeWithComparer (ComparisonIdentity.FromFunction comparer) index count list + [] let sortRange index count list = sortRangeWithComparer ComparisonIdentity.Structural index count list + [] let sortWithComparer (comparer : System.Collections.Generic.IComparer<_>) list = check list; list.Sort(comparer) + [] let sortWith comparer list = sortWithComparer (ComparisonIdentity.FromFunction comparer) list + [] let sort list = check list; list.Sort() ////////// Loop-based ////////// let inline private builderWithLengthOf list = builderWith <| length list + [] let init count initializer = if count < 0 then invalidArg (nameof count) ErrorStrings.InputMustBeNonNegative let builder = builderWith count @@ -147,6 +196,7 @@ module FlatList = builder.Add <| initializer i moveFromBuilder builder + [] let initWithValue count value = if count < 0 then invalidArg (nameof count) ErrorStrings.InputMustBeNonNegative let builder = builderWith count @@ -158,74 +208,103 @@ module FlatList = if i >= length arrs then acc else concatAddLengths arrs (i+1) (acc + arrs.[i].Length) - let concat (seqs:'a seq seq) = seqs |> Seq.concat |> ofSeq + [] + let concat (seqs:FlatList>) = + let builder = builderWith <| concatAddLengths seqs 0 0 + for seq in seqs do + builder.AddRange seq + ofBuilder builder + [] let map mapping = raiseOrReturn >> Seq.map mapping >> ofSeq + [] let countBy projection = raiseOrReturn >> Seq.countBy projection >> ofSeq + [] let indexed list = list |> raiseOrReturn |> Seq.indexed |> ofSeq + [] let iter action = raiseOrReturn >> Seq.iter action + [] let iter2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.iter2 action list1 list2 + [] let distinct (list: FlatList<'T>) = list |> Seq.distinct |> ofSeq + [] let distinctBy projection = raiseOrReturn >> Seq.distinctBy projection >> ofSeq + [] let map2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.map2 mapping list1 list2 |> ofSeq + [] let map3 mapping list1 list2 list3 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 checkNotDefault (nameof list3) list3 Seq.map3 mapping list1 list2 list3 |> ofSeq + + [] let mapi2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.mapi2 mapping list1 list2 |> ofSeq + [] let iteri action = raiseOrReturn >> Seq.iteri action + [] let iteri2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.iteri2 action list1 list2 + [] let mapi mapping = raiseOrReturn >> Seq.mapi mapping >> ofSeq + [] let exists predicate = raiseOrReturn >> Seq.exists predicate + [] let contains e = raiseOrReturn >> Seq.contains e + [] let exists2 predicate list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.exists2 predicate list1 list2 + [] let forall predicate = raiseOrReturn >> Seq.forall predicate + [] let forall2 predicate list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.forall2 predicate list1 list2 + [] let groupBy projection = raiseOrReturn >> Seq.groupBy projection >> Seq.map (fun (k, i) -> k, ofSeq i) >> ofSeq + [] let pick chooser = raiseOrReturn >> Seq.pick chooser + [] let tryPick chooser = raiseOrReturn >> Seq.tryPick chooser + [] let choose chooser = raiseOrReturn >> Seq.choose chooser >> ofSeq + [] let partition predicate list = check list let res1 = builderWith list.Length @@ -235,60 +314,98 @@ module FlatList = if predicate x then res1.Add(x) else res2.Add(x) ofBuilder res1, ofBuilder res2 + [] + let rec iterList (list:FlatList<_>) index predicate indexPredicate indexTransform = + if indexPredicate index then + if predicate list.[index] then + Some (index, list.[index]) + else iterList list (indexTransform index) predicate indexPredicate indexTransform + else None + + [] + let tryFindItem predicate direction list = + check list + let startIndex = if direction then 0 else length list - 1 + let indexPredicate = if direction then ((>) (length list)) else ((<=) 0) + let transform = if direction then ((+) 1) else ((-) 1) + iterList list startIndex predicate indexPredicate transform + + [] let find predicate = raiseOrReturn >> Seq.find predicate + [] let tryFind predicate = raiseOrReturn >> Seq.tryFind predicate + [] let findBack predicate = raiseOrReturn >> Seq.findBack predicate + [] let tryFindBack predicate = raiseOrReturn >> Seq.tryFindBack predicate + [] let findIndex predicate = raiseOrReturn >> Seq.findIndex predicate + [] let findIndexBack predicate = raiseOrReturn >> Seq.findIndexBack predicate + [] let tryFindIndex predicate = raiseOrReturn >> Seq.tryFindIndex predicate + [] let tryFindIndexBack predicate = raiseOrReturn >> Seq.tryFindIndexBack predicate + [] let fold folder (state: 'state) = raiseOrReturn >> Seq.fold folder state + [] let scan folder (state: 'state) = raiseOrReturn >> Seq.scan folder state >> ofSeq + [] let fold2 folder (state: 'state) (left:FlatList<'a>) (right:FlatList<'b>) = check left; check right Seq.fold2 folder state left right + [] let foldBack2 folder (left:FlatList<'a>) (right:FlatList<'b>) (state:'state) = check left; check right Seq.foldBack2 folder left right state + [] let foldBack folder (list:FlatList<'a>) (state: 'state) = check list Seq.foldBack folder list state + [] let scanBack folder (list:FlatList<'a>) (state:'state) = check list Seq.scanBack folder list state |> ofSeq + [] let unfold (generator: 'state -> ('a * 'state) option) state = Seq.unfold generator state |> ofSeq + [] let reduce reduction = raiseOrReturn >> Seq.reduce reduction + [] let reduceBack reduction = raiseOrReturn >> Seq.reduceBack reduction + [] let mapFold mapping (state:'State) (list:FlatList<'T>) = check list let (items, s) = Seq.mapFold mapping state list ofSeq items, s + [] let mapFoldBack mapping (list:FlatList<'T>) (state:'State) = check list let (i, s) = Seq.mapFoldBack mapping list state ofSeq i, s + [] let zip (left:FlatList<_>) (right:FlatList<_>) = check left; check right Seq.zip left right |> ofSeq + [] let zip3 (left:FlatList<_>) (middle:FlatList<_>) (right:FlatList<_>) = check left; check middle; check right Seq.zip3 left middle right |> ofSeq + [] let unzip list = let left = builderWithLengthOf list let right = builderWithLengthOf list @@ -297,6 +414,7 @@ module FlatList = right.Add <| snd item ofBuilder left, ofBuilder right + [] let unzip3 list = let left = builderWithLengthOf list let right = builderWithLengthOf list @@ -307,14 +425,16 @@ module FlatList = right.Add <| thd3 item ofBuilder left, ofBuilder middle, ofBuilder right + [] let windowed windowSize = raiseOrReturn >> Seq.windowed windowSize >> Seq.map ofSeq >> ofSeq + [] let fill target targetIndex count value = mapi (fun i a -> if targetIndex <= i && i < targetIndex + count then value else a) target - |> ofSeq ////////// Based on other operations ////////// + [] let take count list = removeRange count (length list - count) list let inline private lengthWhile predicate list = @@ -323,83 +443,131 @@ module FlatList = while count < list.Length && predicate list.[count] do count <- count + 1 count + + [] let takeWhile predicate list = take (lengthWhile predicate list) list + [] let skip index list = removeRange 0 index list + [] let skipWhile predicate list = skip (lengthWhile predicate list) list + [] let sub start stop list = skip start list |> take (stop - start - 1) + [] let truncate count list = if count < length list then take count list else list + [] let splitAt index list = take index list, skip index list + [] let head list = item 0 list + [] let tryItem index list = if index >= length list || index < 0 then None else Some(list.[index]) + [] let tryHead list = tryItem 0 list + [] let last (list : FlatList<_>) = list.[length list - 1] + [] let tryLast list = tryItem (length list - 1) list + [] let tail list = skip 1 list + [] let tryTail list = if isEmpty list then None else Some <| tail list + [] let create = initWithValue + [] let replicate item = item |> flip initWithValue + [] let collect mapping list = concat <| map mapping list + [] let inline build f = let builder = builder() f builder moveFromBuilder builder + [] let inline update f list = let builder = toBuilder list f builder moveFromBuilder builder + [] let inline sum ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> reduce (+) + [] let inline sumBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> map projection |> reduce (+) + [] let inline average ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt sum length + [] let inline averageBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt ((map projection) >> sum) length - let maxBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> Seq.map projection |> Seq.reduce max - let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> Seq.map projection |> Seq.reduce min + let private minMaxReduction projection comparison a b = + let pa = projection a + let pb = projection b + if comparison pa pb then a else b + + [] + let maxBy projection (list:FlatList<'a>) = list |> raiseOrReturn |> reduce (minMaxReduction projection (>)) + + [] + let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce (minMaxReduction projection (<)) + + [] let max (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce max + [] let min (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce min + [] let sortBy projection = sortWith (applyOverArgs LanguagePrimitives.GenericComparison projection) + [] let sortDescending (list:FlatList<'a>) = sortWith (flip LanguagePrimitives.GenericComparison) list + [] let sortByDescending projection = sortWith (flip (applyOverArgs LanguagePrimitives.GenericComparison projection)) + [] let compareWith comparer (left:FlatList<'a>) (right:FlatList<'b>) = zip left right |> Seq.skipWhile ((uncurry comparer) >> ((=) 0)) |> Seq.head |> (uncurry comparer) + [] let tryExactlyOne (list:FlatList<_>) = Seq.tryExactlyOne list + [] let exactlyOne (list:FlatList<_>) = Seq.exactlyOne list + [] let rev (list:FlatList<_>) = list |> raiseOrReturn |> Seq.rev |> ofSeq + [] let transpose (list:FlatList<_>) = list |> raiseOrReturn |> Seq.transpose |> Seq.map ofSeq |> ofSeq + [] let permute indexMap (list:FlatList<_>) = list |> raiseOrReturn |> Seq.permute indexMap |> ofSeq + [] let pairwise (list:FlatList<_>) = list |> raiseOrReturn |> Seq.pairwise |> ofSeq + [] let except itemsToExclude (list:FlatList<_>) = list |> raiseOrReturn |> Seq.except itemsToExclude |> ofSeq + [] let splitInto count (list:FlatList<_>) = list |> raiseOrReturn |> Seq.splitInto count |> Seq.map ofSeq |> ofSeq + [] let chunkBySize chunkSize (list:FlatList<_>) = list |> raiseOrReturn |> Seq.chunkBySize chunkSize |> Seq.map ofSeq |> ofSeq + [] let allPairs (left:FlatList<'a>) (right:FlatList<'b>) = Seq.allPairs (raiseOrReturn left) (raiseOrReturn right) |> ofSeq ////////// From c0d8313d464f85238aee81d74c6d197db593cdbb Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Tue, 22 Jun 2021 08:22:35 +0300 Subject: [PATCH 18/19] fixes upon review --- src/FSharp.Collections.Immutable/flat-list.fs | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 1c7c3cb..2e974f4 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -224,10 +224,10 @@ module FlatList = [] let indexed list = list |> raiseOrReturn |> Seq.indexed |> ofSeq - [] + [] let iter action = raiseOrReturn >> Seq.iter action - [] + [] let iter2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 @@ -253,22 +253,22 @@ module FlatList = Seq.map3 mapping list1 list2 list3 |> ofSeq - [] + [] let mapi2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.mapi2 mapping list1 list2 |> ofSeq - [] + [] let iteri action = raiseOrReturn >> Seq.iteri action - [] + [] let iteri2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 Seq.iteri2 action list1 list2 - [] + [] let mapi mapping = raiseOrReturn >> Seq.mapi mapping >> ofSeq [] @@ -314,12 +314,11 @@ module FlatList = if predicate x then res1.Add(x) else res2.Add(x) ofBuilder res1, ofBuilder res2 - [] - let rec iterList (list:FlatList<_>) index predicate indexPredicate indexTransform = + let rec private tryFindWithCustomStride (list:FlatList<_>) index predicate indexPredicate indexTransform = if indexPredicate index then if predicate list.[index] then Some (index, list.[index]) - else iterList list (indexTransform index) predicate indexPredicate indexTransform + else tryFindWithCustomStride list (indexTransform index) predicate indexPredicate indexTransform else None [] @@ -327,12 +326,12 @@ module FlatList = check list let startIndex = if direction then 0 else length list - 1 let indexPredicate = if direction then ((>) (length list)) else ((<=) 0) - let transform = if direction then ((+) 1) else ((-) 1) - iterList list startIndex predicate indexPredicate transform + let transform = if direction then ((+) 1) else ((+) -1) // because section is not available + tryFindWithCustomStride list startIndex predicate indexPredicate transform [] let find predicate = raiseOrReturn >> Seq.find predicate - [] + [] let tryFind predicate = raiseOrReturn >> Seq.tryFind predicate [] let findBack predicate = raiseOrReturn >> Seq.findBack predicate @@ -553,7 +552,7 @@ module FlatList = [] let exactlyOne (list:FlatList<_>) = Seq.exactlyOne list - [] + [] let rev (list:FlatList<_>) = list |> raiseOrReturn |> Seq.rev |> ofSeq [] let transpose (list:FlatList<_>) = list |> raiseOrReturn |> Seq.transpose |> Seq.map ofSeq |> ofSeq From 69eb1b9635210d6371342dc2a8ebfb9be6deb53b Mon Sep 17 00:00:00 2001 From: Andrey Sayapin Date: Mon, 8 Aug 2022 14:47:22 +0300 Subject: [PATCH 19/19] amendments - rename checkAndReturn - use ImmutableArrayExtensions in some places - remove ofSeq calls --- src/FSharp.Collections.Immutable/flat-list.fs | 143 ++++++++---------- 1 file changed, 62 insertions(+), 81 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 2e974f4..30adab3 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -4,6 +4,7 @@ namespace global namespace FSharp.Collections.Immutable open FSharp.Collections.Immutable +open System.Linq #endif @@ -20,7 +21,7 @@ module FlatList = if list.IsDefault then invalidArg argName "Uninstantiated ImmutableArray/FlatList" let inline internal check (list : FlatList<'T>) = checkNotDefault (nameof list) list let inline internal checkEmpty (list : FlatList<_>) = check list; if list.Length = 0 then invalidArg (nameof list) "Source is empty" else () - let inline internal raiseOrReturn list = check list; list + let inline internal checkAndReturn list = check list; list ////////// Creating ////////// @@ -41,9 +42,9 @@ module FlatList = [] let inline toSeq (flatList: FlatList<_>) = flatList :> seq<_> [] - let inline toArray (list : FlatList<_>) = check list; Seq.toArray list + let inline toArray (list : FlatList<_>) = ImmutableArrayExtensions.ToArray list [] - let inline toList list = check list; Seq.toList list + let inline toList list = list |> checkAndReturn |> Seq.toList ////////// Building ////////// @@ -149,14 +150,11 @@ module FlatList = /// Removes all the elements that do not match the conditions defined by the specified predicate. [] - let filter predicate list: FlatList<_> = - check list - System.Predicate(not << predicate) - |> list.RemoveAll + let filter predicate list = ImmutableArrayExtensions.Where (list, predicate) /// Removes all the elements that do not match the conditions defined by the specified predicate. [] - let where predicate list = filter predicate list + let where predicate list = ImmutableArrayExtensions.Where (list, predicate) /// Removes a range of elements from the list. [] @@ -204,28 +202,24 @@ module FlatList = builder.Add value ofBuilder builder - let rec private concatAddLengths (arrs: FlatList>) i acc = - if i >= length arrs then acc - else concatAddLengths arrs (i+1) (acc + arrs.[i].Length) - [] let concat (seqs:FlatList>) = - let builder = builderWith <| concatAddLengths seqs 0 0 + let builder = seqs |> Seq.map length |> Seq.sum |> builderWith for seq in seqs do builder.AddRange seq ofBuilder builder [] - let map mapping = raiseOrReturn >> Seq.map mapping >> ofSeq + let map<'a, 'b> (mapping: 'a -> 'b) list = ImmutableArrayExtensions.Select (list, System.Func<'a, 'b> mapping) [] - let countBy projection = raiseOrReturn >> Seq.countBy projection >> ofSeq + let countBy projection = checkAndReturn >> Seq.countBy projection [] - let indexed list = list |> raiseOrReturn |> Seq.indexed |> ofSeq + let indexed list = list |> checkAndReturn |> Seq.indexed [] - let iter action = raiseOrReturn >> Seq.iter action + let iter action = checkAndReturn >> Seq.iter action [] let iter2 action list1 list2 = @@ -234,33 +228,33 @@ module FlatList = Seq.iter2 action list1 list2 [] - let distinct (list: FlatList<'T>) = list |> Seq.distinct |> ofSeq + let distinct (list: FlatList<'T>) = list |> Seq.distinct [] - let distinctBy projection = raiseOrReturn >> Seq.distinctBy projection >> ofSeq + let distinctBy projection = checkAndReturn >> Seq.distinctBy projection [] let map2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - Seq.map2 mapping list1 list2 |> ofSeq + Seq.map2 mapping list1 list2 [] let map3 mapping list1 list2 list3 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 checkNotDefault (nameof list3) list3 - Seq.map3 mapping list1 list2 list3 |> ofSeq + Seq.map3 mapping list1 list2 list3 [] let mapi2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - Seq.mapi2 mapping list1 list2 |> ofSeq + Seq.mapi2 mapping list1 list2 [] - let iteri action = raiseOrReturn >> Seq.iteri action + let iteri action = checkAndReturn >> Seq.iteri action [] let iteri2 action list1 list2 = @@ -269,13 +263,13 @@ module FlatList = Seq.iteri2 action list1 list2 [] - let mapi mapping = raiseOrReturn >> Seq.mapi mapping >> ofSeq + let mapi mapping = checkAndReturn >> Seq.mapi mapping [] - let exists predicate = raiseOrReturn >> Seq.exists predicate + let exists predicate list = ImmutableArrayExtensions.Any (list, System.Func<'a, bool> predicate) [] - let contains e = raiseOrReturn >> Seq.contains e + let contains e = checkAndReturn >> Seq.contains e [] let exists2 predicate list1 list2 = @@ -284,7 +278,7 @@ module FlatList = Seq.exists2 predicate list1 list2 [] - let forall predicate = raiseOrReturn >> Seq.forall predicate + let forall predicate list = ImmutableArrayExtensions.All (list, System.Func<'a, bool> predicate) [] let forall2 predicate list1 list2 = @@ -293,16 +287,16 @@ module FlatList = Seq.forall2 predicate list1 list2 [] - let groupBy projection = raiseOrReturn >> Seq.groupBy projection >> Seq.map (fun (k, i) -> k, ofSeq i) >> ofSeq + let groupBy projection = checkAndReturn >> Seq.groupBy projection [] - let pick chooser = raiseOrReturn >> Seq.pick chooser + let pick chooser = checkAndReturn >> Seq.pick chooser [] - let tryPick chooser = raiseOrReturn >> Seq.tryPick chooser + let tryPick chooser = checkAndReturn >> Seq.tryPick chooser [] - let choose chooser = raiseOrReturn >> Seq.choose chooser >> ofSeq + let choose chooser = checkAndReturn >> Seq.choose chooser [] let partition predicate list = @@ -330,27 +324,27 @@ module FlatList = tryFindWithCustomStride list startIndex predicate indexPredicate transform [] - let find predicate = raiseOrReturn >> Seq.find predicate + let find predicate = checkAndReturn >> Seq.find predicate [] - let tryFind predicate = raiseOrReturn >> Seq.tryFind predicate + let tryFind predicate = checkAndReturn >> Seq.tryFind predicate [] - let findBack predicate = raiseOrReturn >> Seq.findBack predicate + let findBack predicate = checkAndReturn >> Seq.findBack predicate [] - let tryFindBack predicate = raiseOrReturn >> Seq.tryFindBack predicate + let tryFindBack predicate = checkAndReturn >> Seq.tryFindBack predicate [] - let findIndex predicate = raiseOrReturn >> Seq.findIndex predicate + let findIndex predicate = checkAndReturn >> Seq.findIndex predicate [] - let findIndexBack predicate = raiseOrReturn >> Seq.findIndexBack predicate + let findIndexBack predicate = checkAndReturn >> Seq.findIndexBack predicate [] - let tryFindIndex predicate = raiseOrReturn >> Seq.tryFindIndex predicate + let tryFindIndex predicate = checkAndReturn >> Seq.tryFindIndex predicate [] - let tryFindIndexBack predicate = raiseOrReturn >> Seq.tryFindIndexBack predicate + let tryFindIndexBack predicate = checkAndReturn >> Seq.tryFindIndexBack predicate [] - let fold folder (state: 'state) = raiseOrReturn >> Seq.fold folder state + let fold folder (state: 'state) = checkAndReturn >> Seq.fold folder state [] - let scan folder (state: 'state) = raiseOrReturn >> Seq.scan folder state >> ofSeq + let scan folder (state: 'state) = checkAndReturn >> Seq.scan folder state [] let fold2 folder (state: 'state) (left:FlatList<'a>) (right:FlatList<'b>) = @@ -370,39 +364,37 @@ module FlatList = [] let scanBack folder (list:FlatList<'a>) (state:'state) = check list - Seq.scanBack folder list state |> ofSeq + Seq.scanBack folder list state [] let unfold (generator: 'state -> ('a * 'state) option) state = - Seq.unfold generator state |> ofSeq + Seq.unfold generator state [] - let reduce reduction = raiseOrReturn >> Seq.reduce reduction + let reduce reduction = checkAndReturn >> Seq.reduce reduction [] - let reduceBack reduction = raiseOrReturn >> Seq.reduceBack reduction + let reduceBack reduction = checkAndReturn >> Seq.reduceBack reduction [] let mapFold mapping (state:'State) (list:FlatList<'T>) = check list - let (items, s) = Seq.mapFold mapping state list - ofSeq items, s + Seq.mapFold mapping state list [] let mapFoldBack mapping (list:FlatList<'T>) (state:'State) = check list - let (i, s) = Seq.mapFoldBack mapping list state - ofSeq i, s + Seq.mapFoldBack mapping list state [] let zip (left:FlatList<_>) (right:FlatList<_>) = check left; check right - Seq.zip left right |> ofSeq + Seq.zip left right [] let zip3 (left:FlatList<_>) (middle:FlatList<_>) (right:FlatList<_>) = check left; check middle; check right - Seq.zip3 left middle right |> ofSeq + Seq.zip3 left middle right [] let unzip list = @@ -425,7 +417,7 @@ module FlatList = ofBuilder left, ofBuilder middle, ofBuilder right [] - let windowed windowSize = raiseOrReturn >> Seq.windowed windowSize >> Seq.map ofSeq >> ofSeq + let windowed windowSize = checkAndReturn >> Seq.windowed windowSize [] let fill target targetIndex count value = @@ -491,35 +483,24 @@ module FlatList = let replicate item = item |> flip initWithValue [] - let collect mapping list = concat <| map mapping list - - [] - let inline build f = - let builder = builder() - f builder - moveFromBuilder builder - - [] - let inline update f list = - let builder = toBuilder list - f builder - moveFromBuilder builder + let collect mapping list = + ImmutableArrayExtensions.SelectMany (list, System.Func<'a, 'a seq> mapping, System.Func<'a,'a,'a> (fun _ -> id)) [] let inline sum ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = - list |> raiseOrReturn |> reduce (+) + list |> checkAndReturn |> reduce (+) [] let inline sumBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member Zero : ^T) ) = - list |> raiseOrReturn |> map projection |> reduce (+) + list |> checkAndReturn |> map projection |> Seq.sum [] let inline average ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = - list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt sum length + list |> checkAndReturn |> applyOverFuncs LanguagePrimitives.DivideByInt sum length [] let inline averageBy projection ( list:FlatList< ^T > when ^T : (static member (+) : ^T * ^T -> ^T) and ^T : (static member DivideByInt : ^T*int -> ^T) and ^T : (static member Zero : ^T) ) = - list |> raiseOrReturn |> applyOverFuncs LanguagePrimitives.DivideByInt ((map projection) >> sum) length + list |> checkAndReturn |> applyOverFuncs LanguagePrimitives.DivideByInt ((map projection) >> Seq.sum) length let private minMaxReduction projection comparison a b = let pa = projection a @@ -527,15 +508,15 @@ module FlatList = if comparison pa pb then a else b [] - let maxBy projection (list:FlatList<'a>) = list |> raiseOrReturn |> reduce (minMaxReduction projection (>)) + let maxBy projection (list:FlatList<'a>) = list |> checkAndReturn |> reduce (minMaxReduction projection (>)) [] - let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce (minMaxReduction projection (<)) + let minBy projection (list:FlatList<'a> when 'a : comparison) = list |> checkAndReturn |> reduce (minMaxReduction projection (<)) [] - let max (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce max + let max (list:FlatList<'a> when 'a : comparison) = list |> checkAndReturn |> Seq.max [] - let min (list:FlatList<'a> when 'a : comparison) = list |> raiseOrReturn |> reduce min + let min (list:FlatList<'a> when 'a : comparison) = list |> checkAndReturn |> Seq.min [] let sortBy projection = sortWith (applyOverArgs LanguagePrimitives.GenericComparison projection) @@ -553,21 +534,21 @@ module FlatList = let exactlyOne (list:FlatList<_>) = Seq.exactlyOne list [] - let rev (list:FlatList<_>) = list |> raiseOrReturn |> Seq.rev |> ofSeq + let rev (list:FlatList<_>) = list |> checkAndReturn |> Seq.rev [] - let transpose (list:FlatList<_>) = list |> raiseOrReturn |> Seq.transpose |> Seq.map ofSeq |> ofSeq + let transpose (list:FlatList<_>) = list |> checkAndReturn |> Seq.transpose [] - let permute indexMap (list:FlatList<_>) = list |> raiseOrReturn |> Seq.permute indexMap |> ofSeq + let permute indexMap (list:FlatList<_>) = list |> checkAndReturn |> Seq.permute indexMap [] - let pairwise (list:FlatList<_>) = list |> raiseOrReturn |> Seq.pairwise |> ofSeq + let pairwise (list:FlatList<_>) = list |> checkAndReturn |> Seq.pairwise [] - let except itemsToExclude (list:FlatList<_>) = list |> raiseOrReturn |> Seq.except itemsToExclude |> ofSeq + let except itemsToExclude (list:FlatList<_>) = list |> checkAndReturn |> Seq.except itemsToExclude [] - let splitInto count (list:FlatList<_>) = list |> raiseOrReturn |> Seq.splitInto count |> Seq.map ofSeq |> ofSeq + let splitInto count (list:FlatList<_>) = list |> checkAndReturn |> Seq.splitInto count [] - let chunkBySize chunkSize (list:FlatList<_>) = list |> raiseOrReturn |> Seq.chunkBySize chunkSize |> Seq.map ofSeq |> ofSeq + let chunkBySize chunkSize (list:FlatList<_>) = list |> checkAndReturn |> Seq.chunkBySize chunkSize [] - let allPairs (left:FlatList<'a>) (right:FlatList<'b>) = Seq.allPairs (raiseOrReturn left) (raiseOrReturn right) |> ofSeq + let allPairs (left:FlatList<'a>) (right:FlatList<'b>) = Seq.allPairs (checkAndReturn left) (checkAndReturn right) //////////