Skip to content
This repository was archived by the owner on Oct 4, 2020. It is now read-only.

Commit 651f30f

Browse files
authored
Merge pull request #79 from joshuahhh/master
Added toAscUnfoldable
2 parents c673935 + e3d0ddb commit 651f30f

File tree

2 files changed

+49
-29
lines changed

2 files changed

+49
-29
lines changed

src/Data/Map.purs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module Data.Map
2020
, fromFoldableWith
2121
, toList
2222
, toUnfoldable
23+
, toAscUnfoldable
2324
, delete
2425
, pop
2526
, member
@@ -35,15 +36,13 @@ module Data.Map
3536
) where
3637

3738
import Prelude
38-
3939
import Data.Foldable (foldl, foldMap, foldr, class Foldable)
4040
import Data.List (List(..), (:), length, nub)
4141
import Data.Maybe (Maybe(..), maybe, isJust, fromMaybe)
4242
import Data.Monoid (class Monoid)
4343
import Data.Traversable (traverse, class Traversable)
4444
import Data.Tuple (Tuple(Tuple), snd)
4545
import Data.Unfoldable (class Unfoldable, unfoldr)
46-
4746
import Partial.Unsafe (unsafePartial)
4847

4948
-- | `Map k v` represents maps from keys of type `k` to values of type `v`.
@@ -52,14 +51,18 @@ data Map k v
5251
| Two (Map k v) k v (Map k v)
5352
| Three (Map k v) k v (Map k v) k v (Map k v)
5453

54+
-- Internal use
55+
toAscArray :: forall k v. Map k v -> Array (Tuple k v)
56+
toAscArray = toAscUnfoldable
57+
5558
instance eqMap :: (Eq k, Eq v) => Eq (Map k v) where
56-
eq m1 m2 = toList m1 == toList m2
59+
eq m1 m2 = toAscArray m1 == toAscArray m2
5760

5861
instance ordMap :: (Ord k, Ord v) => Ord (Map k v) where
59-
compare m1 m2 = compare (toList m1) (toList m2)
62+
compare m1 m2 = compare (toAscArray m1) (toAscArray m2)
6063

6164
instance showMap :: (Show k, Show v) => Show (Map k v) where
62-
show m = "(fromList " <> show (toList m) <> ")"
65+
show m = "(fromFoldable " <> show (toAscArray m) <> ")"
6366

6467
instance semigroupMap :: Ord k => Semigroup (Map k v) where
6568
append = union
@@ -378,11 +381,10 @@ fromFoldableWith f = foldl (\m (Tuple k v) -> alter (combine v) k m) empty where
378381
combine v (Just v') = Just $ f v v'
379382
combine v Nothing = Just v
380383

381-
-- | Convert a map to a list of key/value pairs
384+
-- | Convert a map to a list of key/value pairs.
385+
-- | DEPRECATED: use toUnfoldable or toAscUnfoldable instead.
382386
toList :: forall k v. Map k v -> List (Tuple k v)
383-
toList Leaf = Nil
384-
toList (Two left k v right) = toList left <> Tuple k v : toList right
385-
toList (Three left k1 v1 mid k2 v2 right) = toList left <> Tuple k1 v1 : toList mid <> Tuple k2 v2 : toList right
387+
toList = toAscUnfoldable
386388

387389
-- | Convert a map to an unfoldable structure of key/value pairs
388390
toUnfoldable :: forall f k v. Unfoldable f => Map k v -> f (Tuple k v)
@@ -395,6 +397,21 @@ toUnfoldable m = unfoldr go (m : Nil) where
395397
Three left k1 v1 mid k2 v2 right ->
396398
Just $ Tuple (Tuple k1 v1) (singleton k2 v2 : left : mid : right : tl)
397399

400+
-- | Convert a map to an unfoldable structure of key/value pairs where the keys are in ascending order
401+
toAscUnfoldable :: forall f k v. Unfoldable f => Map k v -> f (Tuple k v)
402+
toAscUnfoldable m = unfoldr go (m : Nil) where
403+
go Nil = Nothing
404+
go (hd : tl) = case hd of
405+
Leaf -> go tl
406+
Two Leaf k v Leaf ->
407+
Just $ Tuple (Tuple k v) tl
408+
Two Leaf k v right ->
409+
Just $ Tuple (Tuple k v) (right : tl)
410+
Two left k v right ->
411+
go $ left : singleton k v : right : tl
412+
Three left k1 v1 mid k2 v2 right ->
413+
go $ left : singleton k1 v1 : mid : singleton k2 v2 : right : tl
414+
398415
-- | Get a list of the keys contained in a map
399416
keys :: forall k v. Map k v -> List k
400417
keys Leaf = Nil

test/Test/Data/Map.purs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
module Test.Data.Map where
22

33
import Prelude
4-
4+
import Data.List.NonEmpty as NEL
5+
import Data.Map as M
56
import Control.Alt ((<|>))
67
import Control.Monad.Eff (Eff)
78
import Control.Monad.Eff.Console (log, CONSOLE)
89
import Control.Monad.Eff.Exception (EXCEPTION)
910
import Control.Monad.Eff.Random (RANDOM)
10-
1111
import Data.Foldable (foldl, for_, all)
1212
import Data.Function (on)
13-
import Data.List (List(..), groupBy, length, nubBy, sortBy, singleton)
14-
import Data.List.NonEmpty as NEL
15-
import Data.Map as M
13+
import Data.List (List(Cons), groupBy, length, nubBy, singleton, sort, sortBy)
1614
import Data.Maybe (Maybe(..), fromMaybe)
1715
import Data.Tuple (Tuple(..), fst)
18-
1916
import Partial.Unsafe (unsafePartial)
20-
2117
import Test.QuickCheck ((<?>), (===), quickCheck, quickCheck')
2218
import Test.QuickCheck.Arbitrary (class Arbitrary, arbitrary)
2319

@@ -170,7 +166,7 @@ mapTests = do
170166
in M.lookup k tree == Just v <?> ("instrs:\n " <> show instrs <> "\nk:\n " <> show k <> "\nv:\n " <> show v)
171167

172168
log "Singleton to list"
173-
quickCheck $ \k v -> M.toList (M.singleton k v :: M.Map SmallKey Int) == singleton (Tuple k v)
169+
quickCheck $ \k v -> M.toUnfoldable (M.singleton k v :: M.Map SmallKey Int) == singleton (Tuple k v)
174170

175171
log "fromFoldable [] = empty"
176172
quickCheck (M.fromFoldable [] == (M.empty :: M.Map Unit Unit)
@@ -194,21 +190,21 @@ mapTests = do
194190
quickCheck (M.lookup 1 nums == Just 2 <?> "invalid lookup - 1")
195191
quickCheck (M.lookup 2 nums == Nothing <?> "invalid lookup - 2")
196192

197-
log "toList . fromFoldable = id"
198-
quickCheck $ \arr -> let f x = M.toList (M.fromFoldable x)
199-
in f (f arr) == f (arr :: List (Tuple SmallKey Int)) <?> show arr
200-
201-
log "fromFoldable . toList = id"
202-
quickCheck $ \(TestMap m) -> let f m' = M.fromFoldable (M.toList m') in
203-
M.toList (f m) == M.toList (m :: M.Map SmallKey Int) <?> show m
193+
log "sort . toUnfoldable . fromFoldable = sort (on lists without key-duplicates)"
194+
quickCheck $ \(list :: List (Tuple SmallKey Int)) ->
195+
let nubbedList = nubBy ((==) `on` fst) list
196+
f x = M.toUnfoldable (M.fromFoldable x)
197+
in sort (f nubbedList) == sort nubbedList <?> show nubbedList
204198

205199
log "fromFoldable . toUnfoldable = id"
206-
quickCheck $ \(TestMap m) -> let f m' = M.fromFoldable (M.toUnfoldable m' :: List (Tuple SmallKey Int)) in
207-
f m == (m :: M.Map SmallKey Int) <?> show m
200+
quickCheck $ \(TestMap (m :: M.Map SmallKey Int)) ->
201+
let f m' = M.fromFoldable (M.toUnfoldable m' :: List (Tuple SmallKey Int))
202+
in f m == m <?> show m
208203

209204
log "fromFoldableWith const = fromFoldable"
210-
quickCheck $ \arr -> M.fromFoldableWith const arr ==
211-
M.fromFoldable (arr :: List (Tuple SmallKey Int)) <?> show arr
205+
quickCheck $ \arr ->
206+
M.fromFoldableWith const arr ==
207+
M.fromFoldable (arr :: List (Tuple SmallKey Int)) <?> show arr
212208

213209
log "fromFoldableWith (<>) = fromFoldable . collapse with (<>) . group on fst"
214210
quickCheck $ \arr ->
@@ -218,6 +214,12 @@ mapTests = do
218214
groupBy ((==) `on` fst) <<< sortBy (compare `on` fst) in
219215
M.fromFoldableWith (<>) arr === f (arr :: List (Tuple String String))
220216

217+
log "toAscUnfoldable is sorted version of toUnfoldable"
218+
quickCheck $ \(TestMap m) ->
219+
let list = M.toUnfoldable (m :: M.Map SmallKey Int)
220+
ascList = M.toAscUnfoldable m
221+
in ascList === sortBy (compare `on` fst) list
222+
221223
log "Lookup from union"
222224
quickCheck $ \(TestMap m1) (TestMap m2) k ->
223225
M.lookup (smallKey k) (M.union m1 m2) == (case M.lookup k m1 of
@@ -310,5 +312,6 @@ mapTests = do
310312
quickCheck $ \(TestMap m :: TestMap String Int) -> let
311313
f k v = k <> show v
312314
resultViaMapWithKey = m # M.mapWithKey f
313-
resultViaLists = m # M.toList # map (\(Tuple k v) → Tuple k (f k v)) # M.fromFoldable
315+
toList = M.toUnfoldable :: forall k v. M.Map k v -> List (Tuple k v)
316+
resultViaLists = m # toList # map (\(Tuple k v) → Tuple k (f k v)) # M.fromFoldable
314317
in resultViaMapWithKey === resultViaLists

0 commit comments

Comments
 (0)