Skip to content

Commit 8179097

Browse files
authored
Merge pull request #1354 from liboz/master
More efficient Algorithm for List.countBy
2 parents 2a4dc9c + 37551d7 commit 8179097

File tree

3 files changed

+15
-4
lines changed

3 files changed

+15
-4
lines changed

src/fsharp/FSharp.Core/list.fs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@ namespace Microsoft.FSharp.Collections
5353
if dict.TryGetValue(safeKey, &prev) then dict.[safeKey] <- prev + 1 else dict.[safeKey] <- 1
5454
loop t
5555
loop list
56-
let mutable result = []
57-
for group in dict do
58-
result <- (getKey group.Key, group.Value) :: result
59-
result |> rev
56+
Microsoft.FSharp.Primitives.Basics.List.countBy dict getKey
6057

6158
// We avoid wrapping a StructBox, because under 64 JIT we get some "hard" tailcalls which affect performance
6259
let countByValueType (projection:'T->'Key) (list:'T list) = countByImpl HashIdentity.Structural<'Key> projection id list

src/fsharp/FSharp.Core/local.fs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ module internal List =
7272
let cons = freshConsNoTail x
7373
distinctByToFreshConsTail cons hashSet keyf rest
7474
cons
75+
76+
let countBy (dict:Dictionary<_, int>) (keyf:'T -> 'Key) =
77+
let mutable ie = dict.GetEnumerator()
78+
if not (ie.MoveNext()) then []
79+
else
80+
let res = freshConsNoTail (keyf ie.Current.Key, ie.Current.Value)
81+
let mutable cons = res
82+
while ie.MoveNext() do
83+
let cons2 = freshConsNoTail (keyf ie.Current.Key, ie.Current.Value)
84+
setFreshConsTail cons cons2
85+
cons <- cons2
86+
setFreshConsTail cons []
87+
res
7588

7689
let rec mapToFreshConsTail cons f x =
7790
match x with

src/fsharp/FSharp.Core/local.fsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ open Microsoft.FSharp.Collections
88

99
module internal List =
1010
val allPairs : 'T1 list -> 'T2 list -> ('T1 * 'T2) list
11+
val countBy : System.Collections.Generic.Dictionary<'T1, int> -> ('T1 -> 'T2) -> ('T2 * int) list
1112
val distinctWithComparer : System.Collections.Generic.IEqualityComparer<'T> -> 'T list -> 'T list
1213
val distinctByWithComparer : System.Collections.Generic.IEqualityComparer<'Key> -> ('T -> 'Key) -> list:'T list -> 'T list when 'Key : equality
1314
val init : int -> (int -> 'T) -> 'T list

0 commit comments

Comments
 (0)