Skip to content

Commit 6427ae9

Browse files
Add unionWith (#21)
* Add unionWith * Add unionWith * Add unionWith Co-authored-by: Jordan Martinez <[email protected]>
1 parent e48b6bd commit 6427ae9

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
lines changed

src/Foreign/Object.purs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ module Foreign.Object
2828
, keys
2929
, values
3030
, union
31+
, unionWith
3132
, unions
3233
, isSubmap
3334
, fold
@@ -262,6 +263,12 @@ values = toArrayWithKey (\_ v -> v)
262263
union :: forall a. Object a -> Object a -> Object a
263264
union m = mutate (\s -> foldM (\s' k v -> OST.poke k v s') s m)
264265

266+
-- | Compute the union of two maps, using the specified function
267+
-- | to combine values for duplicate keys.
268+
unionWith :: forall a. (a -> a -> a) -> Object a -> Object a -> Object a
269+
unionWith f m1 m2 =
270+
mutate (\s1 -> foldM (\s2 k v1 -> OST.poke k (runFn4 _lookup v1 (\v2 -> f v1 v2) k m2) s2) s1 m1) m2
271+
265272
-- | Compute the union of a collection of maps
266273
unions :: forall f a. Foldable f => f (Object a) -> Object a
267274
unions = foldl union empty

test/Test/Foreign/Object.purs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import Prelude
44

55
import Control.Monad.Writer (runWriter, tell)
66
import Data.Array as A
7-
import Data.Foldable (foldl, foldr)
7+
import Data.Foldable (foldl, foldr, for_)
88
import Data.FoldableWithIndex (foldlWithIndex, foldrWithIndex, foldMapWithIndex)
99
import Data.Function (on)
1010
import Data.List as L
1111
import Data.List.NonEmpty as NEL
12-
import Data.Maybe (Maybe(..))
12+
import Data.Maybe (Maybe(..), fromMaybe)
1313
import Data.Semigroup.First (First(..))
1414
import Data.Semigroup.Last (Last(..))
1515
import Data.Traversable (sequence, traverse)
@@ -181,15 +181,26 @@ objectTests = do
181181
L.groupBy ((==) `on` fst) <<< L.sortBy (compare `on` fst) in
182182
O.fromFoldableWith (<>) arr == f (arr :: L.List (Tuple String String)) <?> show arr
183183

184-
log "Lookup from union"
185-
quickCheck $ \(TestObject m1) (TestObject m2) k ->
186-
O.lookup k (O.union m1 m2) == (case O.lookup k m1 of
187-
Nothing -> O.lookup k m2
188-
Just v -> Just (number v)) <?> ("m1: " <> show m1 <> ", m2: " <> show m2 <> ", k: " <> show k <> ", v1: " <> show (O.lookup k m1) <> ", v2: " <> show (O.lookup k m2) <> ", union: " <> show (O.union m1 m2))
184+
log "unionWith"
185+
for_ [Tuple (+) 0, Tuple (*) 1] $ \(Tuple op ident) ->
186+
quickCheck $ \(TestObject m1) (TestObject m2) k ->
187+
let u = O.unionWith op m1 m2 :: O.Object Int
188+
in case O.lookup k u of
189+
Nothing -> not (O.member k m1 || O.member k m2)
190+
Just v -> v == op (fromMaybe ident (O.lookup k m1)) (fromMaybe ident (O.lookup k m2))
189191

190-
log "Union is idempotent"
191-
quickCheck $ \(TestObject m1) (TestObject m2) ->
192-
(m1 `O.union` m2) == ((m1 `O.union` m2) `O.union` (m2 :: O.Object Int)) <?> (show (O.size (m1 `O.union` m2)) <> " != " <> show (O.size ((m1 `O.union` m2) `O.union` m2)))
192+
log "unionWith argument order"
193+
quickCheck $ \(TestObject m1) (TestObject m2) k ->
194+
let u = O.unionWith (-) m1 m2 :: O.Object Int
195+
in1 = O.member k m1
196+
v1 = O.lookup k m1
197+
in2 = O.member k m2
198+
v2 = O.lookup k m2
199+
in case O.lookup k u of
200+
Just v | in1 && in2 -> Just v == ((-) <$> v1 <*> v2)
201+
Just v | in1 -> Just v == v1
202+
Just v -> Just v == v2
203+
Nothing -> not (in1 || in2)
193204

194205
log "fromFoldable = zip keys values"
195206
quickCheck $ \(TestObject m) -> O.toUnfoldable m == A.zipWith Tuple (O.keys m) (O.values m :: Array Int)

0 commit comments

Comments
 (0)