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

Commit 1760818

Browse files
committed
minView and maxView
1 parent 0ce5038 commit 1760818

File tree

2 files changed

+94
-22
lines changed

2 files changed

+94
-22
lines changed

src/Data/Map.purs

+76-20
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ module Data.Map
1818
, findMax
1919
, deleteMin
2020
, deleteMax
21+
, minView
22+
, maxView
2123
, foldSubmap
2224
, submap
2325
, fromFoldable
@@ -57,7 +59,7 @@ import Data.Traversable (traverse, class Traversable)
5759
import Data.TraversableWithIndex (class TraversableWithIndex, traverseWithIndex)
5860
import Data.Tuple (Tuple(Tuple), snd, uncurry)
5961
import Data.Unfoldable (class Unfoldable, unfoldr)
60-
import Partial.Unsafe (unsafePartial)
62+
import Partial.Unsafe (unsafePartial, unsafeCrashWith)
6163

6264
-- | `Map k v` represents maps from keys of type `k` to values of type `v`.
6365
data Map k v
@@ -298,28 +300,82 @@ findMin = go Nothing
298300
-- | Delete the pair with the least key. O(logn).
299301
-- |
300302
-- | Return an empty map if the map is empty.
301-
deleteMin :: forall k v. Ord k => Map k v -> Map k v
302-
deleteMin Leaf = Leaf
303-
deleteMin n = down Nil n
303+
deleteMin :: forall k. Ord k => Map k ~> Map k
304+
deleteMin = maybe Leaf _.strippedMap <<< minView
305+
306+
-- | Delete the pair with the greatest key. O(logn).
307+
-- |
308+
-- | Return an empty map if the map is empty.
309+
deleteMax :: forall k. Ord k => Map k ~> Map k
310+
deleteMax = maybe Leaf _.strippedMap <<< maxView
311+
312+
-- | Retrieves the least key and the value corresponding to that key,
313+
-- | and the map stripped of that element. O(logn)
314+
-- |
315+
-- | Returns Nothing if the map is empty.
316+
minView
317+
:: forall k v
318+
. Ord k
319+
=> Map k v
320+
-> Maybe { key :: k, value :: v, strippedMap :: Map k v}
321+
minView Leaf = Nothing
322+
minView m = Just $ down Nil m
304323
where
305-
down :: List (TreeContext k v) -> Map k v -> Map k v
306-
down = unsafePartial \ctx -> case _ of
324+
down
325+
:: List (TreeContext k v)
326+
-> Map k v
327+
-> { key :: k, value :: v, strippedMap :: Map k v}
328+
down ctx = case _ of
307329
Two left k v right ->
308330
case left, right of
309-
Leaf, Leaf -> deleteUp ctx Leaf
331+
Leaf, Leaf -> { key: k, value: v, strippedMap: deleteUp ctx Leaf }
310332
_ , _ -> down (Cons (TwoLeft k v right) ctx) left
311333
Three left k1 v1 mid k2 v2 right ->
312334
case left, mid, right of
313-
Leaf, Leaf, Leaf -> fromZipper ctx (Two Leaf k2 v2 Leaf)
335+
Leaf, Leaf, Leaf ->
336+
{ key: k1
337+
, value: v1
338+
, strippedMap: fromZipper ctx (Two Leaf k2 v2 Leaf)
339+
}
314340
_ , _ , _ ->
315341
down (Cons (ThreeLeft k1 v1 mid k2 v2 right) ctx) left
342+
-- using instead of unsafePartial because of a TCO bug:
343+
-- https://github.com/purescript/purescript/issues/3157
344+
Leaf -> unsafeCrashWith "we met a leaf... this shouldn't happen"
316345

317-
-- | Delete the pair with the greatest key. O(logn).
346+
-- | Retrieves the greatest key and the value corresponding to that key,
347+
-- | and the map stripped of that element. O(logn)
318348
-- |
319-
-- | Return an empty map if the map is empty.
320-
deleteMax :: forall k v. Ord k => Map k v -> Map k v
321-
deleteMax Leaf = Leaf
322-
deleteMax n = removeMaxNode Nil n
349+
-- | Returns Nothing if the map is empty.
350+
maxView
351+
:: forall k v
352+
. Ord k
353+
=> Map k v
354+
-> Maybe { key :: k, value :: v, strippedMap :: Map k v}
355+
maxView Leaf = Nothing
356+
maxView n = Just $ down Nil n
357+
where
358+
down
359+
:: List (TreeContext k v)
360+
-> Map k v
361+
-> { key :: k, value :: v, strippedMap :: Map k v}
362+
down ctx = case _ of
363+
Two left k v right ->
364+
case left, right of
365+
Leaf, Leaf -> { key: k, value: v, strippedMap: deleteUp ctx Leaf }
366+
_ , _ -> down (Cons (TwoRight left k v) ctx) right
367+
Three left k1 v1 mid k2 v2 right ->
368+
case left, mid, right of
369+
Leaf, Leaf, Leaf ->
370+
{ key: k2
371+
, value: v2
372+
, strippedMap: fromZipper ctx (Two Leaf k1 v1 Leaf)
373+
}
374+
_ , _ , _ ->
375+
down (Cons (ThreeRight left k1 v1 mid k2 v2) ctx) right
376+
-- using instead of unsafePartial because of a TCO bug:
377+
-- https://github.com/purescript/purescript/issues/3157
378+
Leaf -> unsafeCrashWith "we met a leaf... this shouldn't happen"
323379

324380
-- | Fold over the entries of a given map where the key is between a lower and
325381
-- | an upper bound. Passing `Nothing` as either the lower or upper bound
@@ -526,13 +582,13 @@ pop k = down Nil
526582
Three _ _ _ _ k' v Leaf -> { key: k', value: v }
527583
Three _ _ _ _ _ _ right -> maxNode right
528584

529-
530-
removeMaxNode :: forall k v. Ord k => List (TreeContext k v) -> Map k v -> Map k v
531-
removeMaxNode = unsafePartial \ctx -> case _ of
532-
Two Leaf _ _ Leaf -> deleteUp ctx Leaf
533-
Two left k' v right -> removeMaxNode (Cons (TwoRight left k' v) ctx) right
534-
Three Leaf k1 v1 Leaf _ _ Leaf -> deleteUp (Cons (TwoRight Leaf k1 v1) ctx) Leaf
535-
Three left k1 v1 mid k2 v2 right -> removeMaxNode (Cons (ThreeRight left k1 v1 mid k2 v2) ctx) right
585+
removeMaxNode :: List (TreeContext k v) -> Map k v -> Map k v
586+
removeMaxNode = unsafePartial \ctx m ->
587+
case m of
588+
Two Leaf _ _ Leaf -> deleteUp ctx Leaf
589+
Two left k' v right -> removeMaxNode (Cons (TwoRight left k' v) ctx) right
590+
Three Leaf k1 v1 Leaf _ _ Leaf -> deleteUp (Cons (TwoRight Leaf k1 v1) ctx) Leaf
591+
Three left k1 v1 mid k2 v2 right -> removeMaxNode (Cons (ThreeRight left k1 v1 mid k2 v2) ctx) right
536592

537593
deleteUp :: forall k v. Ord k => List (TreeContext k v) -> Map k v -> Map k v
538594
deleteUp = unsafePartial \ctxs tree ->

test/Test/Data/Map.purs

+18-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import Control.Monad.Eff.Random (RANDOM)
99
import Data.Array as A
1010
import Data.Foldable (foldl, for_, all)
1111
import Data.Function (on)
12-
import Data.List (List(Cons), groupBy, length, nubBy, singleton, sort, sortBy, tail, init)
12+
import Data.List (List(Cons), groupBy, length, nubBy, singleton, sort, sortBy, tail, init, uncons, unsnoc)
1313
import Data.List.NonEmpty as NEL
1414
import Data.Map as M
1515
import Data.Map.Gen (genMap)
16-
import Data.Maybe (Maybe(..), fromMaybe, maybe)
16+
import Data.Maybe (Maybe(..), fromMaybe, maybe, isNothing)
1717
import Data.NonEmpty ((:|))
1818
import Data.Tuple (Tuple(..), fst, uncurry)
1919
import Partial.Unsafe (unsafePartial)
@@ -277,6 +277,22 @@ mapTests = do
277277
quickCheck $ \(TestMap m :: TestMap String Int) ->
278278
M.deleteMax m == maybe m M.fromFoldable (init $ M.toAscUnfoldable m)
279279

280+
log "minView result is correct"
281+
quickCheck $ \(TestMap m :: TestMap String Int) ->
282+
case uncons (M.toAscUnfoldable m) of
283+
Nothing -> isNothing $ M.minView m
284+
Just {head: (Tuple k v), tail} -> unsafePartial
285+
let Just {key: minK, value: minV, strippedMap: sM} = M.minView m
286+
in minK == k && minV == v && sM == (M.fromFoldable tail)
287+
288+
log "maxView result is correct"
289+
quickCheck $ \(TestMap m :: TestMap String Int) ->
290+
case unsnoc (M.toAscUnfoldable m) of
291+
Nothing -> isNothing $ M.minView m
292+
Just {last: (Tuple k v), init} -> unsafePartial
293+
let Just {key: maxK, value: maxV, strippedMap: sM} = M.maxView m
294+
in maxK == k && maxV == v && sM == (M.fromFoldable init)
295+
280296
log "mapWithKey is correct"
281297
quickCheck $ \(TestMap m :: TestMap String Int) -> let
282298
f k v = k <> show v

0 commit comments

Comments
 (0)