From 013b30f08f4d9aed99f68d7a961832462e997ecb Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Thu, 31 Dec 2020 17:01:03 -0800 Subject: [PATCH 1/3] Speedup nubBy: sort array in-place rather than creating new one --- src/Data/Array.purs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Data/Array.purs b/src/Data/Array.purs index 86e8b50d..dd04f0c5 100644 --- a/src/Data/Array.purs +++ b/src/Data/Array.purs @@ -1031,12 +1031,13 @@ nubEq = nubByEq eq nubBy :: forall a. (a -> a -> Ordering) -> Array a -> Array a nubBy comp xs = case head indexedAndSorted of Nothing -> [] - Just x -> map snd $ sortWith fst $ ST.run do + Just x -> map snd $ ST.run do -- TODO: use NonEmptyArrays here to avoid partial functions result <- STA.unsafeThaw $ singleton x ST.foreach indexedAndSorted \pair@(Tuple i x') -> do lst <- snd <<< unsafePartial (fromJust <<< last) <$> STA.unsafeFreeze result when (comp lst x' /= EQ) $ void $ STA.push pair result + _ <- STA.sortWith fst result STA.unsafeFreeze result where indexedAndSorted :: Array (Tuple Int a) From c2c7a08fea5e2af9f703490b375b5b234ec6645f Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Thu, 31 Dec 2020 17:02:55 -0800 Subject: [PATCH 2/3] Speedup nubBy: sort intermediate array in-place rather than creating a new one --- src/Data/Array.purs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Data/Array.purs b/src/Data/Array.purs index dd04f0c5..40a1941d 100644 --- a/src/Data/Array.purs +++ b/src/Data/Array.purs @@ -1041,8 +1041,10 @@ nubBy comp xs = case head indexedAndSorted of STA.unsafeFreeze result where indexedAndSorted :: Array (Tuple Int a) - indexedAndSorted = sortBy (\x y -> comp (snd x) (snd y)) - (mapWithIndex Tuple xs) + indexedAndSorted = ST.run do + arr <- STA.unsafeThaw (mapWithIndex Tuple xs) + _ <- STA.sortBy (\x y -> comp (snd x) (snd y)) arr + STA.unsafeFreeze arr -- | Remove the duplicates from an array, where element equality is determined -- | by the specified equivalence relation, creating a new array. From a98f6ed2b4067d7730f7f0fad40beabe918c06e1 Mon Sep 17 00:00:00 2001 From: Jordan Martinez Date: Thu, 31 Dec 2020 20:58:35 -0800 Subject: [PATCH 3/3] Benchmark nubBy --- bench/Data/Array.purs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/bench/Data/Array.purs b/bench/Data/Array.purs index dc94c7d8..c4d52289 100644 --- a/bench/Data/Array.purs +++ b/bench/Data/Array.purs @@ -3,6 +3,7 @@ module Bench.Data.Array where import Prelude import Data.Array as Array +import Data.Traversable (sequence_) import Data.Maybe (Maybe(..)) import Effect (Effect) import Effect.Console (log) @@ -10,13 +11,17 @@ import Performance.Minibench (benchWith) benchArray :: Effect Unit benchArray = do - log "mapMaybe" - log "---------------" - benchMapMaybe + sequence_ $ Array.intersperse (log "") + [ benchMapMaybe + , benchNubBy + ] + where benchMapMaybe = do + log "mapMaybe" + log "---------------" let shortNats = Array.range 0 100 longNats = Array.range 0 10000 onlyEven x = if x `mod` 2 == 0 then Just x else Nothing @@ -26,3 +31,16 @@ benchArray = do log $ "mapMaybe (" <> show (Array.length longNats) <> ")" benchWith 100 \_ -> Array.mapMaybe onlyEven longNats + + benchNubBy = do + log "nubBy" + log "---------------" + let shortNats = Array.range 0 100 + longNats = Array.range 0 10000 + mod3Cmp x y = compare (x `mod` 3) (y `mod` 3) + + log $ "nubBy (" <> show (Array.length shortNats) <> ")" + benchWith 1000 \_ -> Array.nubBy mod3Cmp shortNats + + log $ "nubBy (" <> show (Array.length longNats) <> ")" + benchWith 100 \_ -> Array.nubBy mod3Cmp longNats