diff --git a/src/Data/List.purs b/src/Data/List.purs index a6cdc36..360b256 100644 --- a/src/Data/List.purs +++ b/src/Data/List.purs @@ -67,8 +67,10 @@ module Data.List , dropWhile , span , group + , groupAll , group' , groupBy + , groupAllBy , partition , nub @@ -115,6 +117,8 @@ import Data.Unfoldable (class Unfoldable, unfoldr) import Data.Foldable (foldl, foldr, foldMap, fold, intercalate, elem, notElem, find, findMap, any, all) as Exports import Data.Traversable (scanl, scanr) as Exports +import Prim.TypeError (class Warn, Text) + -- | Convert a list into any unfoldable structure. -- | -- | Running time: `O(n)` @@ -583,30 +587,57 @@ span _ xs = { init: Nil, rest: xs } -- | For example, -- | -- | ```purescript --- | group (1 : 1 : 2 : 2 : 1 : Nil) == (1 : 1 : Nil) : (2 : 2 : Nil) : (1 : Nil) : Nil +-- | group (1 : 1 : 2 : 2 : 1 : Nil) == +-- | (NonEmptyList (NonEmpty 1 (1 : Nil))) : (NonEmptyList (NonEmpty 2 (2 : Nil))) : (NonEmptyList (NonEmpty 1 Nil)) : Nil -- | ``` -- | -- | Running time: `O(n)` group :: forall a. Eq a => List a -> List (NEL.NonEmptyList a) group = groupBy (==) --- | Sort and then group the elements of a list into lists. +-- | Group equal elements of a list into lists. +-- | +-- | For example, -- | -- | ```purescript --- | group' [1,1,2,2,1] == [[1,1,1],[2,2]] +-- | groupAll (1 : 1 : 2 : 2 : 1 : Nil) == +-- | (NonEmptyList (NonEmpty 1 (1 : 1 : Nil))) : (NonEmptyList (NonEmpty 2 (2 : Nil))) : Nil -- | ``` -group' :: forall a. Ord a => List a -> List (NEL.NonEmptyList a) -group' = group <<< sort +groupAll :: forall a. Ord a => List a -> List (NEL.NonEmptyList a) +groupAll = group <<< sort + +-- | Deprecated previous name of `groupAll`. +group' :: forall a. Warn (Text "'group\'' is deprecated, use groupAll instead") => Ord a => List a -> List (NEL.NonEmptyList a) +group' = groupAll -- | Group equal, consecutive elements of a list into lists, using the specified -- | equivalence relation to determine equality. -- | +-- | For example, +-- | +-- | ```purescript +-- | groupBy (\a b -> odd a && odd b) (1 : 3 : 2 : 4 : 3 : 3 : Nil) == +-- | (NonEmptyList (NonEmpty 1 (3 : Nil))) : (NonEmptyList (NonEmpty 2 Nil)) : (NonEmptyList (NonEmpty 4 Nil)) : (NonEmptyList (NonEmpty 3 (3 : Nil))) : Nil +-- | ``` +-- | -- | Running time: `O(n)` groupBy :: forall a. (a -> a -> Boolean) -> List a -> List (NEL.NonEmptyList a) 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, +-- | +-- | ```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 :: forall a. Ord a => (a -> a -> Boolean) -> List a -> List (NEL.NonEmptyList a) +groupAllBy p = groupBy p <<< sort + -- | Returns a lists of elements which do and do not satisfy a predicate. -- | -- | Running time: `O(n)` diff --git a/src/Data/List/NonEmpty.purs b/src/Data/List/NonEmpty.purs index 7fe595c..9b71508 100644 --- a/src/Data/List/NonEmpty.purs +++ b/src/Data/List/NonEmpty.purs @@ -41,8 +41,10 @@ module Data.List.NonEmpty , dropWhile , span , group + , groupAll , group' , groupBy + , groupAllBy , partition , nub , nubBy @@ -78,6 +80,8 @@ import Data.Semigroup.Foldable (fold1, foldMap1, for1_, sequence1_, traverse1_) import Data.Semigroup.Traversable (sequence1, traverse1, traverse1Default) as Exports import Data.Traversable (scanl, scanr) as Exports +import Prim.TypeError (class Warn, Text) + -- | Internal function: any operation on a list that is guaranteed not to delete -- | all elements also applies to a NEL, this function is a helper for defining -- | those cases. @@ -259,12 +263,18 @@ span = lift <<< L.span group :: forall a. Eq a => NonEmptyList a -> NonEmptyList (NonEmptyList a) group = wrappedOperation "group" L.group -group' :: forall a. Ord a => NonEmptyList a -> NonEmptyList (NonEmptyList a) -group' = wrappedOperation "group'" L.group' +groupAll :: forall a. Ord a => NonEmptyList a -> NonEmptyList (NonEmptyList a) +groupAll = wrappedOperation "groupAll" L.groupAll + +group' :: forall a. Warn (Text "'group\'' is deprecated, use groupAll instead") => Ord a => NonEmptyList a -> NonEmptyList (NonEmptyList a) +group' = 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 = wrappedOperation "groupAllBy" <<< L.groupAllBy + partition :: forall a. (a -> Boolean) -> NonEmptyList a -> { yes :: L.List a, no :: L.List a } partition = lift <<< L.partition diff --git a/test/Test/Data/List.purs b/test/Test/Data/List.purs index 764196d..02b4355 100644 --- a/test/Test/Data/List.purs +++ b/test/Test/Data/List.purs @@ -4,7 +4,7 @@ import Prelude import Data.Foldable (foldMap, foldl) import Data.FoldableWithIndex (foldMapWithIndex, foldlWithIndex, foldrWithIndex) -import Data.List (List(..), (..), stripPrefix, Pattern(..), length, range, foldM, unzip, zip, zipWithA, zipWith, intersectBy, intersect, (\\), deleteBy, delete, unionBy, union, nubBy, nub, groupBy, group', group, partition, span, dropWhile, drop, dropEnd, takeWhile, take, takeEnd, sortBy, sort, catMaybes, mapMaybe, filterM, filter, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, (!!), uncons, unsnoc, init, tail, last, head, insertBy, insert, snoc, null, singleton, fromFoldable, transpose, mapWithIndex, (:)) +import Data.List (List(..), (..), stripPrefix, Pattern(..), length, range, foldM, unzip, zip, zipWithA, zipWith, intersectBy, intersect, (\\), deleteBy, delete, unionBy, union, nubBy, nub, group, groupAll, groupBy, groupAllBy, partition, span, dropWhile, drop, dropEnd, takeWhile, take, takeEnd, sortBy, sort, catMaybes, mapMaybe, filterM, filter, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, (!!), uncons, unsnoc, init, tail, last, head, insertBy, insert, snoc, null, singleton, fromFoldable, transpose, mapWithIndex, (:)) import Data.List.NonEmpty as NEL import Data.Maybe (Maybe(..), isNothing, fromJust) import Data.Monoid.Additive (Additive(..)) @@ -267,12 +267,15 @@ testList = do log "group should group consecutive equal elements into lists" assert $ group (l [1, 2, 2, 3, 3, 3, 1]) == l [NEL.singleton 1, NEL.NonEmptyList (2 :| l [2]), NEL.NonEmptyList (3 :| l [3, 3]), NEL.singleton 1] - log "group' should sort then group consecutive equal elements into lists" - assert $ group' (l [1, 2, 2, 3, 3, 3, 1]) == l [NEL.NonEmptyList (1 :| l [1]), NEL.NonEmptyList (2 :| l [2]), NEL.NonEmptyList (3 :| l [3, 3])] + log "groupAll should group equal elements into lists" + assert $ groupAll (l [1, 2, 2, 3, 3, 3, 1]) == l [NEL.NonEmptyList (1 :| l [1]), NEL.NonEmptyList (2 :| l [2]), NEL.NonEmptyList (3 :| l [3, 3])] 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 "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]) assert $ partitioned.yes == l [5, 3, 4] diff --git a/test/Test/Data/List/NonEmpty.purs b/test/Test/Data/List/NonEmpty.purs index e3cd1ee..3316456 100644 --- a/test/Test/Data/List/NonEmpty.purs +++ b/test/Test/Data/List/NonEmpty.purs @@ -168,12 +168,15 @@ testNonEmptyList = do log "group should group consecutive equal elements into lists" assert $ NEL.group (nel 1 [2, 2, 3, 3, 3, 1]) == nel (nel 1 []) [nel 2 [2], nel 3 [3, 3], nel 1 []] - log "group' should sort then group consecutive equal elements into lists" - assert $ NEL.group' (nel 1 [2, 2, 3, 3, 3, 1]) == nel (nel 1 [1]) [nel 2 [2], nel 3 [3, 3]] + log "groupAll should group equal elements into lists" + assert $ NEL.groupAll (nel 1 [2, 2, 3, 3, 3, 1]) == nel (nel 1 [1]) [nel 2 [2], nel 3 [3, 3]] 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 "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]) assert $ partitioned.yes == l [5, 3, 4]