MyNixOS website logo
Description

Replacement definition of Data.List.GroupBy.

Please see the README on Github at https://github.com/oisdk/groupBy#readme

Build Status

groupBy

This provides a drop-in replacement for Data.List.groupBy, with benchmarks and tests.

The original Data.List.groupBy has (perhaps unexpected) behaviour, in that it compares elements to the first in the group, not adjacent ones. In other words, if you wanted to group into ascending sequences:

>>> Data.List.groupBy (<=) [1,2,2,3,1,2,0,4,5,2]
[[1,2,2,3,1,2],[0,4,5,2]]

The replacement has three distinct advantages:

  1. It groups adjacent elements, allowing the example above to function as expected:

    >>> Data.List.GroupBy.groupBy (<=) [1,2,2,3,1,2,0,4,5,2]
    [[1,2,2,3],[1,2],[0,4,5],[2]]
    
  2. It is a good producer and consumer, with rules similar to those for Data.List.scanl. The old version was defined in terms of span:

    groupBy                 :: (a -> a -> Bool) -> [a] -> [[a]]
    groupBy _  []           =  []
    groupBy eq (x:xs)       =  (x:ys) : groupBy eq zs
                               where (ys,zs) = span (eq x) xs
    

    Which prevents it from being a good producer/consumer.

  3. It is significantly faster than the original in most cases.

Tests

Tests ensure that the function is the same as the original when the relation supplied is an equivalence, and that it performs the expected adjacent comparisons when the relation isn't transitive.

The tests also check that laziness is maintained, as defined by:

>>> head (groupBy (==) (1:2:undefined))
[1]

>>> (head . head) (groupBy undefined (1:undefined))
1

>>> (head . head . tail) (groupBy (==) (1:2:undefined))
2

Benchmarks

Benchmarks compare the function to three other implementations: the current Data.List.groupBy, a version provided by the utility-ht package, and a version provided by Brandon Simmons.

The benchmarks test functions that force the outer list:

length . groupBy eq

And functions which force the contents of the inner lists:

sum' = foldl' (+) 0

sum' . map sum' . groupBy eq

Each benchmark is run on lists where the groups are small, the groups are large, and where there is only one group. The default size is 10000, but other sizes can be provided with the --size=[x,y,z] flag to the benchmarks.

The new definition is slower than the old only when the size of the sublists is much larger than the size of the outer list. To make the newer definition faster in that case, you would simply force the pair (or use a strict pair) from the accumulator. However, this makes the new definition match the old speed in the other cases, which I would imagine are more common.

Metadata

Version

0.1.0.0

License

Platforms (75)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-darwin
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-darwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows