-
Notifications
You must be signed in to change notification settings - Fork 50
Match nub* functions with Array #179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 9 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
1998cd5
Add Eq suffix to original nub/nubBy functions
milesfrain 381a7e5
Add nub/nubBy functions
milesfrain 02f2b38
install quickcheck
milesfrain 300bd31
Revert "install quickcheck"
milesfrain 25d4f49
review feedback - reduce exports, improve docs
milesfrain 83991e4
Merge branch 'master' into nub-ord-rebased
milesfrain 0871480
Use <<< instead of >>>
milesfrain db10d08
Add nub/nubBy for NonEmptyList
milesfrain 6a84b72
Fix CI by updating to rc5
milesfrain ef26a93
Apply indentation feedback
milesfrain 8a6cc41
Copy Map from Data.Map.Internal
MonoidMusician 178f1a2
Specialize to Set
MonoidMusician 7a39c9c
Change to insertAndLookup function
MonoidMusician 7be77fd
Implement nub using Set
MonoidMusician 1273282
Remove unused functions
MonoidMusician 214abe1
Make stack-safe
MonoidMusician 531eac4
Add Lazy nub and nubBy tests
milesfrain 0a3b051
Fix spelling
milesfrain 9360df5
Merge branch 'master' into nub-ord
milesfrain caf19f4
Update changelog
milesfrain 6318e76
Review feedback - test nub on infinite list
milesfrain 1711f13
Spelling fixups
milesfrain eb244d7
Merge branch 'master' into nub-ord
milesfrain a76bcda
Test nubEq on infinite list
milesfrain File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,6 +75,8 @@ module Data.List | |
|
||
, nub | ||
, nubBy | ||
, nubEq | ||
, nubByEq | ||
, union | ||
, unionBy | ||
, delete | ||
|
@@ -101,22 +103,21 @@ import Control.Alt ((<|>)) | |
import Control.Alternative (class Alternative) | ||
import Control.Lazy (class Lazy, defer) | ||
import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM, tailRecM2) | ||
|
||
import Data.Bifunctor (bimap) | ||
import Data.Foldable (class Foldable, foldr, any, foldl) | ||
import Data.Foldable (foldl, foldr, foldMap, fold, intercalate, elem, notElem, find, findMap, any, all) as Exports | ||
import Data.Function (on) | ||
import Data.FunctorWithIndex (mapWithIndex) as FWI | ||
import Data.List.Types (List(..), (:)) | ||
import Data.List.Types (NonEmptyList(..)) as NEL | ||
import Data.Maybe (Maybe(..)) | ||
import Data.Newtype (class Newtype) | ||
import Data.NonEmpty ((:|)) | ||
import Data.Traversable (scanl, scanr) as Exports | ||
import Data.Traversable (sequence) | ||
import Data.Tuple (Tuple(..)) | ||
import Data.Tuple (Tuple(..), fst, snd) | ||
import Data.Unfoldable (class Unfoldable, unfoldr) | ||
|
||
import Data.Foldable (foldl, foldr, foldMap, fold, intercalate, elem, notElem, find, findMap, any, all) as Exports | ||
import Data.Traversable (scanl, scanr) as Exports | ||
|
||
import Prim.TypeError (class Warn, Text) | ||
|
||
-- | Convert a list into any unfoldable structure. | ||
|
@@ -663,18 +664,68 @@ tails list@(Cons _ tl)= list : tails tl | |
-------------------------------------------------------------------------------- | ||
|
||
-- | Remove duplicate elements from a list. | ||
-- | Keeps the first occurrence of each element in the input list, | ||
-- | in the same order they appear in the input list. | ||
-- | | ||
-- | ```purescript | ||
-- | nub 1:2:1:3:3:Nil == 1:2:3:Nil | ||
-- | ``` | ||
-- | | ||
-- | Running time: `O(n log n)` | ||
nub :: forall a. Ord a => List a -> List a | ||
nub = nubBy compare | ||
|
||
-- | Remove duplicate elements from a list based on the provided comparison function. | ||
-- | Keeps the first occurrence of each element in the input list, | ||
-- | in the same order they appear in the input list. | ||
-- | | ||
-- | ```purescript | ||
-- | nubBy (compare `on` Array.length) ([1]:[2]:[3,4]:Nil) == [1]:[3,4]:Nil | ||
-- | ``` | ||
-- | | ||
-- | Running time: `O(n log n)` | ||
nubBy :: forall a. (a -> a -> Ordering) -> List a -> List a | ||
nubBy p = | ||
-- Discard indices, just keep original values. | ||
mapReverse snd | ||
-- Sort by index to recover original order. | ||
-- Use `flip` to sort in reverse order in anticipation of final `mapReverse`. | ||
<<< sortBy (flip compare `on` fst) | ||
-- Removing neighboring duplicates. | ||
<<< nubByAdjacentReverse (\a b -> (p `on` snd) a b == EQ) | ||
-- Sort by original values to cluster duplicates. | ||
<<< sortBy (p `on` snd) | ||
-- Add indices so we can recover original order after deduplicating. | ||
<<< addIndexReverse | ||
|
||
-- | Remove duplicate elements from a list. | ||
-- | Keeps the first occurrence of each element in the input list, | ||
-- | in the same order they appear in the input list. | ||
-- | This less efficient version of `nub` only requires an `Eq` instance. | ||
-- | | ||
-- | ```purescript | ||
-- | nubEq 1:2:1:3:3:Nil == 1:2:3:Nil | ||
-- | ``` | ||
-- | | ||
-- | Running time: `O(n^2)` | ||
nub :: forall a. Eq a => List a -> List a | ||
nub = nubBy eq | ||
nubEq :: forall a. Eq a => List a -> List a | ||
nubEq = nubByEq eq | ||
|
||
-- | Remove duplicate elements from a list, using the specified | ||
-- | function to determine equality of elements. | ||
-- | Remove duplicate elements from a list, using the provided equivalence function. | ||
-- | Keeps the first occurrence of each element in the input list, | ||
-- | in the same order they appear in the input list. | ||
-- | This less efficient version of `nubBy` only requires an equivalence | ||
-- | function, rather than an ordering function. | ||
-- | | ||
-- | ```purescript | ||
-- | mod3eq = eq `on` \n -> mod n 3 | ||
-- | nubByEq mod3eq 1:3:4:5:6:Nil == 1:3:5:Nil | ||
-- | ``` | ||
-- | | ||
-- | Running time: `O(n^2)` | ||
nubBy :: forall a. (a -> a -> Boolean) -> List a -> List a | ||
nubBy _ Nil = Nil | ||
nubBy eq' (x : xs) = x : nubBy eq' (filter (\y -> not (eq' x y)) xs) | ||
nubByEq :: forall a. (a -> a -> Boolean) -> List a -> List a | ||
nubByEq _ Nil = Nil | ||
nubByEq eq' (x : xs) = x : nubByEq eq' (filter (\y -> not (eq' x y)) xs) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was never stack-safe. Reported in #194 |
||
|
||
-- | Calculate the union of two lists. | ||
-- | | ||
|
@@ -687,7 +738,7 @@ union = unionBy (==) | |
-- | | ||
-- | Running time: `O(n^2)` | ||
unionBy :: forall a. (a -> a -> Boolean) -> List a -> List a -> List a | ||
unionBy eq xs ys = xs <> foldl (flip (deleteBy eq)) (nubBy eq ys) xs | ||
milesfrain marked this conversation as resolved.
Show resolved
Hide resolved
|
||
unionBy eq xs ys = xs <> foldl (flip (deleteBy eq)) (nubByEq eq ys) xs | ||
|
||
-- | Delete the first occurrence of an element from a list. | ||
-- | | ||
|
@@ -794,3 +845,62 @@ transpose ((x : xs) : xss) = | |
foldM :: forall m a b. Monad m => (b -> a -> m b) -> b -> List a -> m b | ||
foldM _ b Nil = pure b | ||
foldM f b (a : as) = f b a >>= \b' -> foldM f b' as | ||
|
||
-------------------------------------------------------------------------------- | ||
-- Fast operations which also reverse the list --------------------------------- | ||
-------------------------------------------------------------------------------- | ||
|
||
-- | Maps a function to each element in a list | ||
-- | and reverses the result, but faster than | ||
-- | running each separately. Equivalent to: | ||
-- | | ||
-- | ```purescript | ||
-- | \f l = map f l # reverse | ||
-- | ``` | ||
-- | | ||
-- | Running time: `O(n)` | ||
mapReverse :: forall a b. (a -> b) -> List a -> List b | ||
mapReverse f = go Nil | ||
where | ||
go :: List b -> List a -> List b | ||
go acc Nil = acc | ||
go acc (x : xs) = go (f x : acc) xs | ||
|
||
-- | Converts each element to a Tuple containing its index, | ||
-- | and reverses the result, but faster than running separately. | ||
-- | Equivalent to: | ||
-- | | ||
-- | ```purescript | ||
-- | reverse <<< mapWithIndex Tuple | ||
-- | ``` | ||
-- | | ||
-- | Running time: `O(n)` | ||
addIndexReverse :: forall a. List a -> List (Tuple Int a) | ||
addIndexReverse = go 0 Nil | ||
where | ||
go :: Int -> List (Tuple Int a) -> List a -> List (Tuple Int a) | ||
go i acc Nil = acc | ||
go i acc (x : xs) = go (i + 1) ((Tuple i x) : acc) xs | ||
|
||
-- | Removes neighboring duplicate items from a list | ||
-- | based on an equality predicate. | ||
-- | Keeps the LAST element if duplicates are encountered. | ||
-- | Returned list is reversed (this is to improve performance). | ||
-- | | ||
-- | ```purescript | ||
-- | nubByAdjacentReverse (on eq length) ([1]:[2]:[3,4]:Nil) == [3,4]:[2]:Nil` | ||
-- | ``` | ||
-- | | ||
-- | Running time: `O(n)` | ||
nubByAdjacentReverse :: forall a. (a -> a -> Boolean) -> List a -> List a | ||
nubByAdjacentReverse p = go Nil | ||
where | ||
go :: List a -> List a -> List a | ||
-- empty output | ||
go Nil (x : xs) = go (x : Nil) xs | ||
-- checking for duplicates | ||
go acc@(a : as) (x : xs) | ||
| p a x = go (x : as) xs | ||
| otherwise = go (x : acc) xs | ||
-- empty input | ||
go acc Nil = acc | ||
milesfrain marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.