diff --git a/src/Data/Array.purs b/src/Data/Array.purs index 86e8b50d..e90d8c02 100644 --- a/src/Data/Array.purs +++ b/src/Data/Array.purs @@ -79,6 +79,11 @@ module Data.Array , mapMaybe , catMaybes , mapWithIndex + , foldl + , foldr + , foldMap + , fold + , intercalate , scanl , scanr @@ -124,8 +129,6 @@ module Data.Array , foldRecM , unsafeIndex - - , module Exports ) where import Prelude @@ -138,8 +141,8 @@ import Control.Monad.ST as ST import Data.Array.NonEmpty.Internal (NonEmptyArray(..)) import Data.Array.ST as STA import Data.Array.ST.Iterator as STAI -import Data.Foldable (class Foldable, foldl, foldr, traverse_) -import Data.Foldable (foldl, foldr, foldMap, fold, intercalate) as Exports +import Data.Foldable (class Foldable, traverse_) +import Data.Foldable as F import Data.Maybe (Maybe(..), maybe, isJust, fromJust, isNothing) import Data.Traversable (sequence, traverse) import Data.Tuple (Tuple(..), fst, snd) @@ -164,7 +167,7 @@ toUnfoldable xs = unfoldr f 0 -- | ``` -- | fromFoldable :: forall f. Foldable f => f ~> Array -fromFoldable = fromFoldableImpl foldr +fromFoldable = fromFoldableImpl F.foldr foreign import fromFoldableImpl :: forall f a @@ -765,6 +768,21 @@ modifyAtIndices :: forall t a. Foldable t => t Int -> (a -> a) -> Array a -> Arr modifyAtIndices is f xs = ST.run (STA.withArray (\res -> traverse_ (\i -> STA.modify i f res) is) xs) +foldl :: forall a b. (b -> a -> b) -> b -> Array a -> b +foldl = F.foldl + +foldr :: forall a b. (a -> b -> b) -> b -> Array a -> b +foldr = F.foldr + +foldMap :: forall a m. Monoid m => (a -> m) -> Array a -> m +foldMap = F.foldMap + +fold :: forall m. Monoid m => Array m -> m +fold = F.fold + +intercalate :: forall a. Monoid a => a -> Array a -> a +intercalate = F.intercalate + -- | Fold a data structure from the left, keeping all intermediate results -- | instead of only the final result. Note that the initial value does not -- | appear in the result (unlike Haskell's `Prelude.scanl`). diff --git a/src/Data/Array/NonEmpty.purs b/src/Data/Array/NonEmpty.purs index bbc51af8..67cca9e3 100644 --- a/src/Data/Array/NonEmpty.purs +++ b/src/Data/Array/NonEmpty.purs @@ -32,8 +32,12 @@ module Data.Array.NonEmpty , unsnoc , (!!), index + , elem + , notElem , elemIndex , elemLastIndex + , find + , findMap , findIndex , findLastIndex , insertAt @@ -44,15 +48,24 @@ module Data.Array.NonEmpty , modifyAtIndices , alterAt + , intersperse , reverse , concat , concatMap , filter - , splitAt , partition + , splitAt , filterA , mapMaybe , catMaybes + , mapWithIndex + , foldl1 + , foldr1 + , foldMap1 + , fold1 + , intercalate + , scanl + , scanr , sort , sortBy @@ -116,6 +129,7 @@ import Data.Foldable (class Foldable) import Data.Maybe (Maybe(..), fromJust) import Data.NonEmpty (NonEmpty, (:|)) import Data.Semigroup.Foldable (class Foldable1) +import Data.Semigroup.Foldable as F import Data.Tuple (Tuple(..)) import Data.Unfoldable (class Unfoldable) import Data.Unfoldable1 (class Unfoldable1, unfoldr1) @@ -247,14 +261,26 @@ index = adaptAny A.index infixl 8 index as !! +elem :: forall a. Eq a => a -> NonEmptyArray a -> Boolean +elem x = adaptAny $ A.elem x + +notElem :: forall a. Eq a => a -> NonEmptyArray a -> Boolean +notElem x = adaptAny $ A.notElem x + elemIndex :: forall a. Eq a => a -> NonEmptyArray a -> Maybe Int elemIndex x = adaptAny $ A.elemIndex x elemLastIndex :: forall a. Eq a => a -> NonEmptyArray a -> Maybe Int elemLastIndex x = adaptAny $ A.elemLastIndex x +find :: forall a. (a -> Boolean) -> NonEmptyArray a -> Maybe a +find p = adaptAny $ A.find p + +findMap :: forall a b. (a -> Maybe b) -> NonEmptyArray a -> Maybe b +findMap p = adaptAny $ A.findMap p + findIndex :: forall a. (a -> Boolean) -> NonEmptyArray a -> Maybe Int -findIndex x = adaptAny $ A.findIndex x +findIndex p = adaptAny $ A.findIndex p findLastIndex :: forall a. (a -> Boolean) -> NonEmptyArray a -> Maybe Int findLastIndex x = adaptAny $ A.findLastIndex x @@ -280,6 +306,9 @@ modifyAtIndices is f = unsafeAdapt $ A.modifyAtIndices is f alterAt :: forall a. Int -> (a -> Maybe a) -> NonEmptyArray a -> Maybe (Array a) alterAt i f = A.alterAt i f <<< toArray +intersperse :: forall a. a -> NonEmptyArray a -> NonEmptyArray a +intersperse x = unsafeAdapt $ A.intersperse x + reverse :: forall a. NonEmptyArray a -> NonEmptyArray a reverse = unsafeAdapt A.reverse @@ -316,6 +345,30 @@ mapMaybe f = adaptAny $ A.mapMaybe f catMaybes :: forall a. NonEmptyArray (Maybe a) -> Array a catMaybes = adaptAny A.catMaybes +mapWithIndex :: forall a b. (Int -> a -> b) -> NonEmptyArray a -> NonEmptyArray b +mapWithIndex f = unsafeAdapt $ A.mapWithIndex f + +foldl1 :: forall a. (a -> a -> a) -> NonEmptyArray a -> a +foldl1 = F.foldl1 + +foldr1 :: forall a. (a -> a -> a) -> NonEmptyArray a -> a +foldr1 = F.foldr1 + +foldMap1 :: forall a m. Semigroup m => (a -> m) -> NonEmptyArray a -> m +foldMap1 = F.foldMap1 + +fold1 :: forall m. Semigroup m => NonEmptyArray m -> m +fold1 = F.fold1 + +intercalate :: forall a. Semigroup a => a -> NonEmptyArray a -> a +intercalate = F.intercalate + +scanl :: forall a b. (b -> a -> b) -> b -> NonEmptyArray a -> NonEmptyArray b +scanl f x = unsafeAdapt $ A.scanl f x + +scanr :: forall a b. (a -> b -> b) -> b -> NonEmptyArray a -> NonEmptyArray b +scanr f x = unsafeAdapt $ A.scanr f x + sort :: forall a. Ord a => NonEmptyArray a -> NonEmptyArray a sort = unsafeAdapt A.sort diff --git a/test/Test/Data/Array.purs b/test/Test/Data/Array.purs index 5621ed95..9325c0f8 100644 --- a/test/Test/Data/Array.purs +++ b/test/Test/Data/Array.purs @@ -270,7 +270,7 @@ testArray = do assert $ A.scanl (-) 10 [1,2,3] == [9, 7, 4] log "scanl should return the same results as its Foldable counterpart" - assert $ A.scanl (+) 0 [1,2,3] == scanl (+) 0 [1,2,3] + assert $ A.scanl (+) 0 [1,2,3] == scanl (+) 0 [1,2,3] assert $ A.scanl (-) 10 [1,2,3] == scanl (-) 10 [1,2,3] log "scanr should return an array that stores the accumulated value at each step" diff --git a/test/Test/Data/Array/NonEmpty.purs b/test/Test/Data/Array/NonEmpty.purs index cb183df1..7f2a9fca 100644 --- a/test/Test/Data/Array/NonEmpty.purs +++ b/test/Test/Data/Array/NonEmpty.purs @@ -6,7 +6,7 @@ import Data.Array as A import Data.Array.NonEmpty as NEA import Data.Const (Const(..)) import Data.Foldable (for_, sum, traverse_) -import Data.FunctorWithIndex (mapWithIndex) +import Data.Traversable (scanl, scanr) import Data.Maybe (Maybe(..), fromJust) import Data.Monoid.Additive (Additive(..)) import Data.NonEmpty ((:|)) @@ -102,6 +102,14 @@ testNonEmptyArray = do assert $ NEA.index (fromArray [1, 2, 3]) 6 == Nothing assert $ NEA.index (fromArray [1, 2, 3]) (-1) == Nothing + log "elem should return true if the array contains the given element at least once" + assert $ NEA.elem 1 (fromArray [1, 2, 1]) == true + assert $ NEA.elem 4 (fromArray [1, 2, 1]) == false + + log "notElem should return true if the array does not contain the given element" + assert $ NEA.notElem 1 (fromArray [1, 2, 1]) == false + assert $ NEA.notElem 4 (fromArray [1, 2, 1]) == true + log "elemIndex should return the index of an item that a predicate returns true for in an array" assert $ NEA.elemIndex 1 (fromArray [1, 2, 1]) == Just 0 assert $ NEA.elemIndex 4 (fromArray [1, 2, 1]) == Nothing @@ -110,6 +118,15 @@ testNonEmptyArray = do assert $ NEA.elemLastIndex 1 (fromArray [1, 2, 1]) == Just 2 assert $ NEA.elemLastIndex 4 (fromArray [1, 2, 1]) == Nothing + log "find should return the first element for which a predicate returns true in an array" + assert $ NEA.find (_ == 1) (fromArray [1, 2, 1]) == Just 1 + assert $ NEA.find (_ == 3) (fromArray [1, 2, 1]) == Nothing + + log "findMap should return the mapping of the first element that satisfies the given predicate" + assert $ NEA.findMap (\x -> if x > 3 then Just x else Nothing) (fromArray [1, 2, 4]) == Just 4 + assert $ NEA.findMap (\x -> if x > 3 then Just x else Nothing) (fromArray [1, 2, 1]) == Nothing + assert $ NEA.findMap (\x -> if x > 3 then Just x else Nothing) (fromArray [4, 1, 5]) == Just 4 + log "findIndex should return the index of an item that a predicate returns true for in an array" assert $ (NEA.findIndex (_ /= 1) (fromArray [1, 2, 1])) == Just 1 assert $ (NEA.findIndex (_ == 3) (fromArray [1, 2, 1])) == Nothing @@ -158,6 +175,13 @@ testNonEmptyArray = do log "alterAt should return Nothing if the index is out of NEA.range" assert $ NEA.alterAt 1 (Just <<< (_ + 1)) (NEA.singleton 1) == Nothing + log "intersperse should return the original array when given an array with one element" + assert $ NEA.intersperse " " (NEA.singleton "a") == NEA.singleton "a" + + log "intersperse should insert the given element in-between each element in an array with two or more elements" + assert $ NEA.intersperse " " (fromArray ["a", "b"]) == fromArray ["a", " ", "b"] + assert $ NEA.intersperse 0 (fromArray [ 1, 2, 3, 4, 5 ]) == fromArray [ 1, 0, 2, 0, 3, 0, 4, 0, 5 ] + log "reverse should reverse the order of items in an array" assert $ NEA.reverse (fromArray [1, 2, 3]) == fromArray [3, 2, 1] assert $ NEA.reverse (NEA.singleton 0) == NEA.singleton 0 @@ -193,7 +217,23 @@ testNonEmptyArray = do assert $ NEA.catMaybes (fromArray [Nothing, Just 2, Nothing, Just 4]) == [2, 4] log "mapWithIndex applies a function with an index for every element" - assert $ mapWithIndex (\i x -> x - i) (fromArray [9,8,7,6,5]) == fromArray [9,7,5,3,1] + assert $ NEA.mapWithIndex (\i x -> x - i) (fromArray [9,8,7,6,5]) == fromArray [9,7,5,3,1] + + log "scanl should return an array that stores the accumulated value at each step" + assert $ NEA.scanl (+) 0 (fromArray [1,2,3]) == fromArray [1, 3, 6] + assert $ NEA.scanl (-) 10 (fromArray [1,2,3]) == fromArray [9, 7, 4] + + log "scanl should return the same results as its Foldable counterpart" + assert $ NEA.scanl (+) 0 (fromArray [1,2,3]) == scanl (+) 0 (fromArray [1,2,3]) + assert $ NEA.scanl (-) 10 (fromArray [1,2,3]) == scanl (-) 10 (fromArray [1,2,3]) + + log "scanr should return an array that stores the accumulated value at each step" + assert $ NEA.scanr (+) 0 (fromArray [1,2,3]) == fromArray [6,5,3] + assert $ NEA.scanr (flip (-)) 10 (fromArray [1,2,3]) == fromArray [4,5,7] + + log "scanr should return the same results as its Foldable counterpart" + assert $ NEA.scanr (+) 0 (fromArray [1,2,3]) == scanr (+) 0 (fromArray [1,2,3]) + assert $ NEA.scanr (flip (-)) 10 (fromArray [1,2,3]) == scanr (flip (-)) 10 (fromArray [1,2,3]) log "updateAtIndices changes the elements at specified indices" assert $ NEA.updateAtIndices