@@ -37,12 +37,12 @@ module CollectionExtensions =
3737 module internal Readers =
3838 /// Reader for ASet.sortBy
3939 [<Sealed>]
40- type SetSortByReader < 'T1 , 'T2 when 'T2 : comparison >( set : aset < 'T1 >, projection : 'T1 -> 'T2 ) =
40+ type SetSortByReader < 'T1 , 'T2 when 'T2 : comparison >( set : aset < 'T1 >, projection : 'T1 -> 'T2 , cmp : System.Collections.Generic.IComparer < 'T2 > ) =
4141 inherit AbstractReader< IndexListDelta< 'T1>>( IndexListDelta.empty)
4242
4343 let reader = set.GetReader()
4444 let mapping = IndexMapping< Unique< 'T2>>()
45- let cache = Cache< 'T1, Unique< 'T2>>( projection >> Unique)
45+ let cache = Cache< 'T1, Unique< 'T2>>( fun v -> Unique( projection v , cmp ) )
4646
4747 override x.Compute ( token : AdaptiveToken ) =
4848 reader.GetChanges token |> Seq.choose ( fun op ->
@@ -200,6 +200,56 @@ module CollectionExtensions =
200200 |> IndexListDelta.toSeq
201201 |> HashMapDelta.ofSeq
202202
203+ [<Sealed>]
204+ type MapSortByReader < 'K , 'V , 'T when 'T : comparison >( map : amap < 'K , 'V >, cmp : System.Collections.Generic.IComparer < 'T >, projection : OptimizedClosures.FSharpFunc < 'K , 'V , 'T >) =
205+ inherit AbstractReader< IndexListDelta< 'K * 'V>>( IndexListDelta.empty)
206+
207+ let reader = map.GetReader()
208+
209+ let mapping =
210+ CustomIndexMapping< int * 'T>( fun ( k0 , t0 ) ( k1 , t1 ) ->
211+ let c = cmp.Compare( t0, t1)
212+ if c <> 0 then c
213+ else compare k0 k1
214+ )
215+ let mutable state = HashMap.empty< 'K, int * 'T>
216+ let mutable currentId = 0
217+
218+ let newId () =
219+ let i = currentId
220+ currentId <- i + 1
221+ i
222+
223+ override x.Compute ( token : AdaptiveToken ) =
224+ let ops = reader.GetChanges token
225+ let mutable res = MapExt.empty
226+ for key, op in ops do
227+ match op with
228+ | Set v ->
229+ let id =
230+ match HashMap.tryFind key state with
231+ | Some ( i, _) -> i
232+ | None -> newId()
233+
234+ let t = projection.Invoke( key, v)
235+ let index = mapping.Invoke( id, t)
236+ res <- MapExt.add index ( Set ( key, v)) res
237+ state <- HashMap.add key ( id, t) state
238+ | Remove ->
239+ match HashMap.tryRemove key state with
240+ | Some (( id, t), rest) ->
241+ state <- rest
242+ match mapping.Revoke( id, t) with
243+ | Some index ->
244+ res <- MapExt.add index ( Remove) res
245+ | None ->
246+ ()
247+ | None ->
248+ ()
249+
250+ IndexListDelta( res)
251+
252+
203253
204254 /// Functional operators for amap<_ ,_ >
205255 [<CompilationRepresentation( CompilationRepresentationFlags.ModuleSuffix) >]
@@ -249,6 +299,37 @@ module CollectionExtensions =
249299 ListToMapReader( list) :> _
250300 }
251301
302+ /// Creates a sorted alist holding Key/Value tuples from the amap using the given projection.
303+ let sortBy ( projection : 'K -> 'V -> 'T ) ( map : amap < 'K , 'V >) : alist < 'K * 'V > =
304+ if map.IsConstant then
305+ map
306+ |> AMap.force
307+ |> HashMap.toList
308+ |> List.sortBy ( fun ( k , v ) -> projection k v)
309+ |> AList.ofList
310+ else
311+ AList.ofReader <| fun () ->
312+ MapSortByReader( map, LanguagePrimitives.FastGenericComparer, OptimizedClosures.FSharpFunc<_,_,_>. Adapt projection)
313+
314+ /// Creates a sorted (descending order) alist holding Key/Value tuples from the amap using the given projection.
315+ let sortByDescending ( projection : 'K -> 'V -> 'T ) ( map : amap < 'K , 'V >) : alist < 'K * 'V > =
316+ if map.IsConstant then
317+ map
318+ |> AMap.force
319+ |> HashMap.toList
320+ |> List.sortByDescending ( fun ( k , v ) -> projection k v)
321+ |> AList.ofList
322+ else
323+ AList.ofReader <| fun () ->
324+ let cmp =
325+ let c = LanguagePrimitives.FastGenericComparer
326+ { new System.Collections.Generic.IComparer< 'T> with
327+ member x.Compare ( a , b ) = c.Compare( b, a)
328+ }
329+ MapSortByReader( map, cmp, OptimizedClosures.FSharpFunc<_,_,_>. Adapt projection)
330+
331+
332+
252333
253334 /// Functional operators for aset<_ >
254335 [<CompilationRepresentation( CompilationRepresentationFlags.ModuleSuffix) >]
@@ -302,11 +383,31 @@ module CollectionExtensions =
302383 |> Seq.map snd
303384 |> AList.ofSeq
304385 else
305- AList.ofReader ( fun () -> SetSortByReader( set, projection))
386+ AList.ofReader ( fun () -> SetSortByReader( set, projection, LanguagePrimitives.FastGenericComparer < 'T2 > ))
306387
307388 /// Sorts the set.
308389 let inline sort ( set : aset < 'T >) = sortWith compare set
309390
391+ /// Sorts the set in descending order.
392+ let inline sortDescending ( set : aset < 'T >) = sortWith ( fun a b -> compare b a) set
393+
394+ /// Sorts the set using the keys given by projection in descending order.
395+ let sortByDescending ( projection : 'T1 -> 'T2 ) ( set : aset < 'T1 >) =
396+ if set.IsConstant then
397+ set.Content
398+ |> AVal.force
399+ |> Seq.indexed
400+ |> Seq.sortByDescending ( fun ( i , v ) -> projection v, - i)
401+ |> Seq.map snd
402+ |> AList.ofSeq
403+ else
404+ let cmp =
405+ let c = LanguagePrimitives.FastGenericComparer< 'T2>
406+ { new System.Collections.Generic.IComparer< 'T2> with
407+ member x.Compare ( a , b ) = c.Compare( b, a)
408+ }
409+ AList.ofReader ( fun () -> SetSortByReader( set, projection, cmp))
410+
310411 /// Creates an alist from the set with undefined element order.
311412 let toAList ( set : aset < 'T >) =
312413 if set.IsConstant then
0 commit comments