diff --git a/CHANGELOG.md b/CHANGELOG.md index a3c961b..99915e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Breaking changes: - Update project and deps to PureScript v0.15.0 (#203 by @JordanMartinez) - Drop deprecated `MonadZero` instance (#205 by @JordanMartinez) - Drop deprecated `group'` and `mapWithIndex` (#206 by @JordanMartinez) +- Change `groupAllBy` to use a comparison function (#191) New features: @@ -43,7 +44,7 @@ Breaking changes: New features: - Added `nubEq`/`nubByEq` (#179) -- Added `groupAllBy` (#182, #191) +- Added `groupAllBy` (#182) - Added `Eq1` and `Ord1` instances to `NonEmptyList` and `LazyNonEmptyList` (#188) Bugfixes: diff --git a/src/Data/List.purs b/src/Data/List.purs index fc99156..38f9036 100644 --- a/src/Data/List.purs +++ b/src/Data/List.purs @@ -611,17 +611,16 @@ groupBy _ Nil = Nil groupBy eq (x : xs) = case span (eq x) xs of { init: ys, rest: zs } -> NEL.NonEmptyList (x :| ys) : groupBy eq zs --- | Group equal elements of a list into lists, using the specified --- | equivalence relation to determine equality. --- | --- | For example, +-- | Sort, then group equal elements of a list into lists, using the provided comparison function. -- | -- | ```purescript --- | groupAllBy (\a b -> odd a && odd b) (1 : 3 : 2 : 4 : 3 : 3 : Nil) == --- | (NonEmptyList (NonEmpty 1 Nil)) : (NonEmptyList (NonEmpty 2 Nil)) : (NonEmptyList (NonEmpty 3 (3 : 3 : Nil))) : (NonEmptyList (NonEmpty 4 Nil)) : Nil +-- | groupAllBy (compare `on` (_ `div` 10)) (32 : 31 : 21 : 22 : 11 : 33 : Nil) == +-- | NonEmptyList (11 :| Nil) : NonEmptyList (21 :| 22 : Nil) : NonEmptyList (32 :| 31 : 33) : Nil -- | ``` -groupAllBy :: forall a. Ord a => (a -> a -> Boolean) -> List a -> List (NEL.NonEmptyList a) -groupAllBy p = groupBy p <<< sort +-- | +-- | Running time: `O(n log n)` +groupAllBy :: forall a. (a -> a -> Ordering) -> List a -> List (NEL.NonEmptyList a) +groupAllBy p = groupBy (\x y -> p x y == EQ) <<< sortBy p -- | Returns a lists of elements which do and do not satisfy a predicate. -- | diff --git a/src/Data/List/NonEmpty.purs b/src/Data/List/NonEmpty.purs index ffb72ea..42fa49e 100644 --- a/src/Data/List/NonEmpty.purs +++ b/src/Data/List/NonEmpty.purs @@ -260,7 +260,7 @@ groupAll = wrappedOperation "groupAll" L.groupAll groupBy :: forall a. (a -> a -> Boolean) -> NonEmptyList a -> NonEmptyList (NonEmptyList a) groupBy = wrappedOperation "groupBy" <<< L.groupBy -groupAllBy :: forall a. Ord a => (a -> a -> Boolean) -> NonEmptyList a -> NonEmptyList (NonEmptyList a) +groupAllBy :: forall a. (a -> a -> Ordering) -> NonEmptyList a -> NonEmptyList (NonEmptyList a) groupAllBy = wrappedOperation "groupAllBy" <<< L.groupAllBy partition :: forall a. (a -> Boolean) -> NonEmptyList a -> { yes :: L.List a, no :: L.List a } diff --git a/test/Test/Data/List.purs b/test/Test/Data/List.purs index d94450b..a96b6d7 100644 --- a/test/Test/Data/List.purs +++ b/test/Test/Data/List.purs @@ -3,7 +3,7 @@ module Test.Data.List (testList) where import Prelude import Data.Array as Array -import Data.Foldable (foldMap, foldl) +import Data.Foldable (class Foldable, foldMap, foldl) import Data.FoldableWithIndex (foldMapWithIndex, foldlWithIndex, foldrWithIndex) import Data.Function (on) import Data.List (List(..), Pattern(..), alterAt, catMaybes, concat, concatMap, delete, deleteAt, deleteBy, drop, dropEnd, dropWhile, elemIndex, elemLastIndex, filter, filterM, findIndex, findLastIndex, foldM, fromFoldable, group, groupAll, groupAllBy, groupBy, head, init, insert, insertAt, insertBy, intersect, intersectBy, last, length, mapMaybe, modifyAt, nub, nubBy, nubByEq, nubEq, null, partition, range, reverse, singleton, snoc, sort, sortBy, span, stripPrefix, tail, take, takeEnd, takeWhile, transpose, uncons, union, unionBy, unsnoc, unzip, updateAt, zip, zipWith, zipWithA, (!!), (..), (:), (\\)) @@ -23,7 +23,11 @@ import Test.Assert (assert) testList :: Effect Unit testList = do - let l = fromFoldable + let + l = fromFoldable + + nel :: forall f a. Foldable f => a -> f a -> NEL.NonEmptyList a + nel x xs = NEL.NonEmptyList $ x :| fromFoldable xs log "strip prefix" assert $ stripPrefix (Pattern (1:Nil)) (1:2:Nil) == Just (2:Nil) @@ -272,8 +276,8 @@ testList = do log "groupBy should group consecutive equal elements into lists based on an equivalence relation" assert $ groupBy (\x y -> odd x && odd y) (l [1, 1, 2, 2, 3, 3]) == l [NEL.NonEmptyList (1 :| l [1]), NEL.singleton 2, NEL.singleton 2, NEL.NonEmptyList (3 :| l [3])] - log "groupAllBy should group equal elements into lists based on an equivalence relation" - assert $ groupAllBy (\x y -> odd x && odd y) (l [1, 3, 2, 4, 3, 3]) == l [NEL.singleton 1, NEL.singleton 2, NEL.NonEmptyList (3 :| l [3, 3]), NEL.singleton 4] + log "groupAllBy should sort then group equal elements into lists based on a comparison function" + assert $ groupAllBy (compare `on` (_ `div` 10)) (l [32, 31, 21, 22, 11, 33]) == l [nel 11 [], nel 21 [22], nel 32 [31, 33]] log "partition should separate a list into a tuple of lists that do and do not satisfy a predicate" let partitioned = partition (_ > 2) (l [1, 5, 3, 2, 4]) diff --git a/test/Test/Data/List/NonEmpty.purs b/test/Test/Data/List/NonEmpty.purs index 665338e..6ad71c1 100644 --- a/test/Test/Data/List/NonEmpty.purs +++ b/test/Test/Data/List/NonEmpty.purs @@ -21,9 +21,9 @@ import Test.Assert (assert) testNonEmptyList :: Effect Unit testNonEmptyList = do let - nel :: ∀ f a. Foldable f => a -> f a -> NEL.NonEmptyList a + nel :: forall f a. Foldable f => a -> f a -> NEL.NonEmptyList a nel x xs = NEL.NonEmptyList $ x :| L.fromFoldable xs - l :: ∀ f a. Foldable f => f a -> L.List a + l :: forall f a. Foldable f => f a -> L.List a l = L.fromFoldable log "singleton should construct a non-empty list with a single value" @@ -173,8 +173,8 @@ testNonEmptyList = do log "groupBy should group consecutive equal elements into lists based on an equivalence relation" assert $ NEL.groupBy (\x y -> odd x && odd y) (nel 1 [1, 2, 2, 3, 3]) == nel (nel 1 [1]) [nel 2 [], nel 2 [], nel 3 [3]] - log "groupAllBy should group equal elements into lists based on an equivalence relation" - assert $ NEL.groupAllBy (\x y -> odd x && odd y) (nel 1 [3, 2, 4, 3, 3]) == nel (nel 1 []) [nel 2 [], nel 3 [3, 3], nel 4 []] + log "groupAllBy should sort then group equal elements into lists based on a comparison function" + assert $ NEL.groupAllBy (compare `on` (_ `div` 10)) (nel 32 [31, 21, 22, 11, 33]) == nel (nel 11 []) [nel 21 [22], nel 32 [31, 33]] log "partition should separate a list into a tuple of lists that do and do not satisfy a predicate" let partitioned = NEL.partition (_ > 2) (nel 1 [5, 3, 2, 4])