Skip to content

Commit

Permalink
+ List.chunkBy
Browse files Browse the repository at this point in the history
  • Loading branch information
gusty committed Oct 21, 2023
1 parent 1a5e595 commit 38c7549
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/FSharpPlus/Control/Collection.fs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ type GroupBy =
type ChunkBy =
static member ChunkBy (x: Id<'T> , f: 'T->'Key, _: Id<'Key*Id<'T>> , [<Optional>]_impl: ChunkBy) = let a = Id.run x in Id.create (f a, x)
static member ChunkBy (x: seq<'T> , f: 'T->'Key, _: seq<'Key*seq<'T>> , [<Optional>]_impl: ChunkBy) = Seq.chunkBy f x |> Seq.map (fun (x,y) -> x, y :> _ seq)
static member ChunkBy (x: list<'T>, f: 'T->'Key, _: list<'Key*list<'T>>, [<Optional>]_impl: ChunkBy) = Seq.chunkBy f x |> Seq.map (fun (x,y) -> x, Seq.toList y) |> Seq.toList
static member ChunkBy (x: list<'T>, f: 'T->'Key, _: list<'Key*list<'T>>, [<Optional>]_impl: ChunkBy) = List.chunkBy f x
static member ChunkBy (x: 'T [] , f: 'T->'Key, _: ('Key*('T [])) [] , [<Optional>]_impl: ChunkBy) = Seq.chunkBy f x |> Seq.map (fun (x,y) -> x, Seq.toArray y) |> Seq.toArray

static member inline Invoke (projection: 'T->'Key) (source: '``Collection<'T>``) : '``Collection<'Key * 'Collection<'T>>`` =
Expand Down
38 changes: 38 additions & 0 deletions src/FSharpPlus/Extensions/List.fs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,44 @@ module List =
loop (ls,rs)
loop (list1, list2)
#endif

/// <summary>
/// Chunks the list up into groups with the same projected key by applying
/// the key-generating projection function to each element and yielding a list of
/// keys tupled with values.
/// </summary>
///
/// <remarks>
/// Each key is tupled with an array of all adjacent elements that match
/// to the key, therefore keys are not unique but can't be adjacent
/// as each time the key changes a new group is yield.
///
/// The ordering of the original list is respected.
/// </remarks>
///
/// <param name="projection">A function that transforms an element of the list into a comparable key.</param>
/// <param name="source">The input list.</param>
///
/// <returns>The resulting list of keys tupled with a list of matching values</returns>
let chunkBy (projection: 'T -> 'Key) (source: _ list) =
match source with
| [] -> []
| x::xs ->
let mutable acc = new ListCollector<_> ()
let mutable members = new ListCollector<_> ()
let rec loop source g =
match source with
| [] -> acc.Add (g, members.Close ())
| x::xs ->
let key = projection x
if g <> key then
acc.Add (g, members.Close ())
members <- new ListCollector<_> ()
members.Add x
loop xs key
members.Add x
loop xs (projection x)
acc.Close ()

/// <summary>Same as choose but with access to the index.</summary>
/// <param name="mapping">The mapping function, taking index and element as parameters.</param>
Expand Down

0 comments on commit 38c7549

Please sign in to comment.