diff --git a/src/Data/Array.js b/src/Data/Array.js index 8f0d63d3..e0f85d72 100644 --- a/src/Data/Array.js +++ b/src/Data/Array.js @@ -307,6 +307,30 @@ exports.zipWith = function (f) { }; }; +//------------------------------------------------------------------------------ +// Folding --------------------------------------------------------------------- +//------------------------------------------------------------------------------ + +exports.any = function (p) { + return function (xs) { + var len = xs.length; + for (var i = 0; i < len; i++) { + if (p(xs[i])) return true; + } + return false; + }; +}; + +exports.all = function (p) { + return function (xs) { + var len = xs.length; + for (var i = 0; i < len; i++) { + if (!p(xs[i])) return false; + } + return true; + }; +}; + //------------------------------------------------------------------------------ // Partial --------------------------------------------------------------------- //------------------------------------------------------------------------------ diff --git a/src/Data/Array.purs b/src/Data/Array.purs index 0364390a..811081d8 100644 --- a/src/Data/Array.purs +++ b/src/Data/Array.purs @@ -115,6 +115,9 @@ module Data.Array , zip , unzip + , any + , all + , foldM , foldRecM @@ -134,7 +137,7 @@ 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, any, all) as Exports +import Data.Foldable (foldl, foldr, foldMap, fold, intercalate) as Exports import Data.Maybe (Maybe(..), maybe, isJust, fromJust, isNothing) import Data.Traversable (sequence, traverse) import Data.Tuple (Tuple(..), fst, snd) @@ -1035,7 +1038,7 @@ nubByEq :: forall a. (a -> a -> Boolean) -> Array a -> Array a nubByEq eq xs = ST.run do arr <- STA.empty ST.foreach xs \x -> do - e <- not <<< Exports.any (_ `eq` x) <$> (STA.unsafeFreeze arr) + e <- not <<< any (_ `eq` x) <$> (STA.unsafeFreeze arr) when e $ void $ STA.push x arr STA.unsafeFreeze arr @@ -1192,6 +1195,28 @@ unzip xs = snds' <- STA.unsafeFreeze snds pure $ Tuple fsts' snds' +-- | Returns true if at least one array element satisfies the given predicate, +-- | iterating the array only as necessary and stopping as soon as the predicate +-- | yields true. +-- | +-- | ```purescript +-- | any (_ > 0) [] = False +-- | any (_ > 0) [-1, 0, 1] = True +-- | any (_ > 0) [-1, -2, -3] = False +-- | ``` +foreign import any :: forall a. (a -> Boolean) -> Array a -> Boolean + +-- | Returns true if all the array elements satisfy the given predicate. +-- | iterating the array only as necessary and stopping as soon as the predicate +-- | yields false. +-- | +-- | ```purescript +-- | all (_ > 0) [] = True +-- | all (_ > 0) [1, 2, 3] = True +-- | all (_ > 0) [-1, -2, -3] = False +-- | ``` +foreign import all :: forall a. (a -> Boolean) -> Array a -> Boolean + -- | Perform a fold using a monadic step function. -- | -- | ```purescript diff --git a/src/Data/Array/NonEmpty.purs b/src/Data/Array/NonEmpty.purs index 0f9d4415..be90f846 100644 --- a/src/Data/Array/NonEmpty.purs +++ b/src/Data/Array/NonEmpty.purs @@ -89,6 +89,9 @@ module Data.Array.NonEmpty , zip , unzip + , any + , all + , foldM , foldRecM @@ -438,6 +441,12 @@ zip xs ys = unsafeFromArray $ toArray xs `A.zip` toArray ys unzip :: forall a b. NonEmptyArray (Tuple a b) -> Tuple (NonEmptyArray a) (NonEmptyArray b) unzip = bimap unsafeFromArray unsafeFromArray <<< A.unzip <<< toArray +any :: forall a. (a -> Boolean) -> NonEmptyArray a -> Boolean +any p = adaptAny $ A.any p + +all :: forall a. (a -> Boolean) -> NonEmptyArray a -> Boolean +all p = adaptAny $ A.all p + foldM :: forall m a b. Monad m => (b -> a -> m b) -> b -> NonEmptyArray a -> m b foldM f acc = adaptAny $ A.foldM f acc diff --git a/test/Test/Data/Array.purs b/test/Test/Data/Array.purs index 08174c4f..e1b7f460 100644 --- a/test/Test/Data/Array.purs +++ b/test/Test/Data/Array.purs @@ -415,6 +415,16 @@ testArray = do log "unzip should deconstruct a list of tuples into a tuple of lists" assert $ A.unzip [Tuple 1 "a", Tuple 2 "b", Tuple 3 "c"] == Tuple [1, 2, 3] ["a", "b", "c"] + log "any should return true if at least one array element satisfy the given predicate" + assert $ not $ A.any (_ > 0) [] + assert $ A.any (_ > 0) [-1, 0, 1] + assert $ not $ A.any (_ > 0) [-1, -2, -3] + + log "all should return true if all the array elements satisfy the given predicate" + assert $ A.all (_ > 0) [] + assert $ A.all (_ > 0) [1, 2, 3] + assert $ not $ A.all (_ > 0) [-1, -2, -3] + log "foldM should perform a fold using a monadic step function" assert $ A.foldM (\x y -> Just (x + y)) 0 (A.range 1 10) == Just 55 assert $ A.foldM (\_ _ -> Nothing) 0 (A.range 1 10) == Nothing diff --git a/test/Test/Data/Array/NonEmpty.purs b/test/Test/Data/Array/NonEmpty.purs index b42c08e9..9db55f4d 100644 --- a/test/Test/Data/Array/NonEmpty.purs +++ b/test/Test/Data/Array/NonEmpty.purs @@ -285,6 +285,14 @@ testNonEmptyArray = do log "unzip should deconstruct a list of tuples into a tuple of lists" assert $ NEA.unzip (fromArray [Tuple 1 "a", Tuple 2 "b", Tuple 3 "c"]) == Tuple (fromArray [1, 2, 3]) (fromArray ["a", "b", "c"]) + log "any should return true if at least one array element satisfy the given predicate" + assert $ NEA.any (_ > 0) $ fromArray [-1, 0, 1] + assert $ not $ NEA.any (_ > 0) $ fromArray [-1, -2, -3] + + log "all should return true if all the array elements satisfy the given predicate" + assert $ NEA.all (_ > 0) $ fromArray [1, 2, 3] + assert $ not $ NEA.all (_ > 0) $ fromArray [-1, -2, -3] + log "fromFoldable" for_ (fromArray [[], [1], [1,2], [1,2,3,4,5]]) \xs -> do assert $ NEA.fromFoldable xs == NEA.fromArray xs