diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef197a9..6f1270f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,22 +5,24 @@ Notable changes to this project are documented in this file. The format is based
 ## [Unreleased]
 
 Breaking changes:
-- Rename `scanrLazy` to `scanlLazy` and fix parameter ordering (#161)
-- Rename `group'` to `groupAll` (#182)
-- Change `Alt ZipList` to satisfy distributivity (#150)
+- Converted `nub`/`nubBy` to use ordering, rather than equality (#179)
+- Renamed `scanrLazy` to `scanlLazy` and fixed parameter ordering (#161)
+- Renamed `group'` to `groupAll` (#182)
+- Changed `Alt ZipList` to satisfy distributivity (#150)
 
 New features:
-- Add `groupAllBy` (#182, #191) 
+- Added `nubEq`/`nubByEq` (#179)
+- Added `groupAllBy` (#182, #191) 
 - Added `Eq1` and `Ord1` instances to `NonEmptyList` and `LazyNonEmptyList` (#188)
 
 Bugfixes:
 
 Other improvements:
-- Fix Lazy List docs where original list is returned instead of Nothing (#169)
-- Migrate to GitHub Actions (#177)
-- Change `foldM` type signature to more closely match `foldl` (#165)
-- Improve `foldr` performance on large lists (#180)
-- Generate changelog and add PR template (#187) 
+- Fixed Lazy List docs where original list is returned instead of Nothing (#169)
+- Migrated to GitHub Actions (#177)
+- Changed `foldM` type signature to more closely match `foldl` (#165)
+- Improved `foldr` performance on large lists (#180)
+- Generated changelog and add PR template (#187) 
 
 ## [v5.4.1](https://github.com/purescript/purescript-lists/releases/tag/v5.4.1) - 2019-05-06
 
diff --git a/src/Data/List.purs b/src/Data/List.purs
index 360b256..b697202 100644
--- a/src/Data/List.purs
+++ b/src/Data/List.purs
@@ -75,6 +75,8 @@ module Data.List
 
   , nub
   , nubBy
+  , nubEq
+  , nubByEq
   , union
   , unionBy
   , delete
@@ -101,22 +103,20 @@ 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.FunctorWithIndex (mapWithIndex) as FWI
+import Data.List.Internal (emptySet, insertAndLookupBy)
 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.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 +663,64 @@ 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 = reverse <<< go emptySet Nil
+  where
+    go _ acc Nil = acc
+    go s acc (a : as) =
+      let { found, result: s' } = insertAndLookupBy p a s
+      in if found
+        then go s' acc as
+        else go s' (a : acc) as
+
+-- | 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)
 
 -- | Calculate the union of two lists.
 -- |
@@ -687,7 +733,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
+unionBy eq xs ys = xs <> foldl (flip (deleteBy eq)) (nubByEq eq ys) xs
 
 -- | Delete the first occurrence of an element from a list.
 -- |
diff --git a/src/Data/List/Internal.purs b/src/Data/List/Internal.purs
new file mode 100644
index 0000000..5f5c950
--- /dev/null
+++ b/src/Data/List/Internal.purs
@@ -0,0 +1,63 @@
+module Data.List.Internal (Set, emptySet, insertAndLookupBy) where
+
+import Prelude
+
+import Data.List.Types (List(..))
+
+data Set k
+  = Leaf
+  | Two (Set k) k (Set k)
+  | Three (Set k) k (Set k) k (Set k)
+
+emptySet :: forall k. Set k
+emptySet = Leaf
+
+data TreeContext k
+  = TwoLeft k (Set k)
+  | TwoRight (Set k) k
+  | ThreeLeft k (Set k) k (Set k)
+  | ThreeMiddle (Set k) k k (Set k)
+  | ThreeRight (Set k) k (Set k) k
+
+fromZipper :: forall k. List (TreeContext k) -> Set k -> Set k
+fromZipper Nil tree = tree
+fromZipper (Cons x ctx) tree =
+  case x of
+    TwoLeft k1 right -> fromZipper ctx (Two tree k1 right)
+    TwoRight left k1 -> fromZipper ctx (Two left k1 tree)
+    ThreeLeft k1 mid k2 right -> fromZipper ctx (Three tree k1 mid k2 right)
+    ThreeMiddle left k1 k2 right -> fromZipper ctx (Three left k1 tree k2 right)
+    ThreeRight left k1 mid k2 -> fromZipper ctx (Three left k1 mid k2 tree)
+
+data KickUp k = KickUp (Set k) k (Set k)
+
+-- | Insert or replace a key/value pair in a map
+insertAndLookupBy :: forall k. (k -> k -> Ordering) -> k -> Set k -> { found :: Boolean, result :: Set k }
+insertAndLookupBy comp k orig = down Nil orig
+  where
+  down :: List (TreeContext k) -> Set k -> { found :: Boolean, result :: Set k }
+  down ctx Leaf = { found: false, result: up ctx (KickUp Leaf k Leaf) }
+  down ctx (Two left k1 right) =
+    case comp k k1 of
+      EQ -> { found: true, result: orig }
+      LT -> down (Cons (TwoLeft k1 right) ctx) left
+      _  -> down (Cons (TwoRight left k1) ctx) right
+  down ctx (Three left k1 mid k2 right) =
+    case comp k k1 of
+      EQ -> { found: true, result: orig }
+      c1 ->
+        case c1, comp k k2 of
+          _ , EQ -> { found: true, result: orig }
+          LT, _  -> down (Cons (ThreeLeft k1 mid k2 right) ctx) left
+          GT, LT -> down (Cons (ThreeMiddle left k1 k2 right) ctx) mid
+          _ , _  -> down (Cons (ThreeRight left k1 mid k2) ctx) right
+
+  up :: List (TreeContext k) -> KickUp k -> Set k
+  up Nil (KickUp left k' right) = Two left k' right
+  up (Cons x ctx) kup =
+    case x, kup of
+      TwoLeft k1 right, KickUp left k' mid -> fromZipper ctx (Three left k' mid k1 right)
+      TwoRight left k1, KickUp mid k' right -> fromZipper ctx (Three left k1 mid k' right)
+      ThreeLeft k1 c k2 d, KickUp a k' b -> up ctx (KickUp (Two a k' b) k1 (Two c k2 d))
+      ThreeMiddle a k1 k2 d, KickUp b k' c -> up ctx (KickUp (Two a k1 b) k' (Two c k2 d))
+      ThreeRight a k1 b k2, KickUp c k' d -> up ctx (KickUp (Two a k1 b) k2 (Two c k' d))
diff --git a/src/Data/List/Lazy.purs b/src/Data/List/Lazy.purs
index f3e4a63..24ed8b9 100644
--- a/src/Data/List/Lazy.purs
+++ b/src/Data/List/Lazy.purs
@@ -72,6 +72,8 @@ module Data.List.Lazy
 
   , nub
   , nubBy
+  , nubEq
+  , nubByEq
   , union
   , unionBy
   , delete
@@ -103,6 +105,7 @@ import Control.Monad.Rec.Class as Rec
 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.Lazy (defer)
+import Data.List.Internal (emptySet, insertAndLookupBy)
 import Data.List.Lazy.Types (List(..), Step(..), step, nil, cons, (:))
 import Data.List.Lazy.Types (NonEmptyList(..)) as NEL
 import Data.Maybe (Maybe(..), isNothing)
@@ -590,21 +593,45 @@ partition f = foldr go {yes: nil, no: nil}
 -- Set-like operations ---------------------------------------------------------
 --------------------------------------------------------------------------------
 
+-- | 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.
+-- |
+-- | 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.
+-- |
+-- | Running time: `O(n log n)`
+nubBy :: forall a. (a -> a -> Ordering) -> List a -> List a
+nubBy p = go emptySet
+  where
+    go s (List l) = List (map (goStep s) l)
+    goStep _ Nil = Nil
+    goStep s (Cons a as) =
+      let { found, result: s' } = insertAndLookupBy p a s
+      in if found
+        then step (go s' as)
+        else Cons a (go s' as)
+
 -- | Remove duplicate elements from a list.
 -- |
 -- | 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.
 -- |
 -- | Running time: `O(n^2)`
-nubBy :: forall a. (a -> a -> Boolean) -> List a -> List a
-nubBy eq = List <<< map go <<< unwrap
+nubByEq :: forall a. (a -> a -> Boolean) -> List a -> List a
+nubByEq eq = List <<< map go <<< unwrap
   where
   go Nil = Nil
-  go (Cons x xs) = Cons x (nubBy eq (filter (\y -> not (eq x y)) xs))
+  go (Cons x xs) = Cons x (nubByEq eq (filter (\y -> not (eq x y)) xs))
 
 -- | Calculate the union of two lists.
 -- |
@@ -617,7 +644,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
+unionBy eq xs ys = xs <> foldl (flip (deleteBy eq)) (nubByEq eq ys) xs
 
 -- | Delete the first occurrence of an element from a list.
 -- |
diff --git a/src/Data/List/NonEmpty.purs b/src/Data/List/NonEmpty.purs
index 9b71508..49eace0 100644
--- a/src/Data/List/NonEmpty.purs
+++ b/src/Data/List/NonEmpty.purs
@@ -48,6 +48,8 @@ module Data.List.NonEmpty
   , partition
   , nub
   , nubBy
+  , nubEq
+  , nubByEq
   , union
   , unionBy
   , intersect
@@ -278,12 +280,18 @@ groupAllBy = wrappedOperation "groupAllBy" <<< L.groupAllBy
 partition :: forall a. (a -> Boolean) -> NonEmptyList a -> { yes :: L.List a, no :: L.List a }
 partition = lift <<< L.partition
 
-nub :: forall a. Eq a => NonEmptyList a -> NonEmptyList a
+nub :: forall a. Ord a => NonEmptyList a -> NonEmptyList a
 nub = wrappedOperation "nub" L.nub
 
-nubBy :: forall a. (a -> a -> Boolean) -> NonEmptyList a -> NonEmptyList a
+nubBy :: forall a. (a -> a -> Ordering) -> NonEmptyList a -> NonEmptyList a
 nubBy = wrappedOperation "nubBy" <<< L.nubBy
 
+nubEq :: forall a. Eq a => NonEmptyList a -> NonEmptyList a
+nubEq = wrappedOperation "nubEq" L.nubEq
+
+nubByEq :: forall a. (a -> a -> Boolean) -> NonEmptyList a -> NonEmptyList a
+nubByEq = wrappedOperation "nubByEq" <<< L.nubByEq
+
 union :: forall a. Eq a => NonEmptyList a -> NonEmptyList a -> NonEmptyList a
 union = wrappedOperation2 "union" L.union
 
diff --git a/test/Test/Data/List.purs b/test/Test/Data/List.purs
index 02b4355..5ac2db8 100644
--- a/test/Test/Data/List.purs
+++ b/test/Test/Data/List.purs
@@ -2,9 +2,11 @@ module Test.Data.List (testList) where
 
 import Prelude
 
+import Data.Array as Array
 import Data.Foldable (foldMap, foldl)
 import Data.FoldableWithIndex (foldMapWithIndex, foldlWithIndex, foldrWithIndex)
-import Data.List (List(..), (..), stripPrefix, Pattern(..), length, range, foldM, unzip, zip, zipWithA, zipWith, intersectBy, intersect, (\\), deleteBy, delete, unionBy, union, nubBy, nub, group, groupAll, groupBy, groupAllBy, partition, span, dropWhile, drop, dropEnd, takeWhile, take, takeEnd, sortBy, sort, catMaybes, mapMaybe, filterM, filter, concat, concatMap, reverse, alterAt, modifyAt, updateAt, deleteAt, insertAt, findLastIndex, findIndex, elemLastIndex, elemIndex, (!!), uncons, unsnoc, init, tail, last, head, insertBy, insert, snoc, null, singleton, fromFoldable, transpose, mapWithIndex, (:))
+import Data.Function (on)
+import Data.List (List(..), Pattern(..), alterAt, catMaybes, concat, concatMap, delete, deleteAt, deleteBy, drop, dropEnd, dropWhile, elemIndex, elemLastIndex, filter, filterM, findIndex, findLastIndex, foldM, fromFoldable, group, groupAll, groupAllBy, groupBy, head, init, insert, insertAt, insertBy, intersect, intersectBy, last, length, mapMaybe, mapWithIndex, modifyAt, nub, nubBy, nubByEq, nubEq, null, partition, range, reverse, singleton, snoc, sort, sortBy, span, stripPrefix, tail, take, takeEnd, takeWhile, transpose, uncons, union, unionBy, unsnoc, unzip, updateAt, zip, zipWith, zipWithA, (!!), (..), (:), (\\))
 import Data.List.NonEmpty as NEL
 import Data.Maybe (Maybe(..), isNothing, fromJust)
 import Data.Monoid.Additive (Additive(..))
@@ -37,7 +39,7 @@ testList = do
   assert $ (range 0 5) == l [0, 1, 2, 3, 4, 5]
   assert $ (range 2 (-3)) == l [2, 1, 0, -1, -2, -3]
 
-  log "replicate should produce an list containg an item a specified number of times"
+  log "replicate should produce an list containing an item a specified number of times"
   assert $ replicate 3 true == l [true, true, true]
   assert $ replicate 1 "foo" == l ["foo"]
   assert $ replicate 0 "foo" == l []
@@ -281,12 +283,19 @@ testList = do
   assert $ partitioned.yes == l [5, 3, 4]
   assert $ partitioned.no == l [1, 2]
 
-  log "nub should remove duplicate elements from the list, keeping the first occurence"
+  log "nub should remove duplicate elements from the list, keeping the first occurrence"
   assert $ nub (l [1, 2, 2, 3, 4, 1]) == l [1, 2, 3, 4]
 
   log "nubBy should remove duplicate items from the list using a supplied predicate"
-  let nubPred = \x y -> if odd x then false else x == y
-  assert $ nubBy nubPred (l [1, 2, 2, 3, 3, 4, 4, 1]) == l [1, 2, 3, 3, 4, 1]
+  let nubPred = compare `on` Array.length
+  assert $ nubBy nubPred (l [[1],[2],[3,4]]) == l [[1],[3,4]]
+
+  log "nubEq should remove duplicate elements from the list, keeping the first occurrence"
+  assert $ nubEq (l [1, 2, 2, 3, 4, 1]) == l [1, 2, 3, 4]
+
+  log "nubByEq should remove duplicate items from the list using a supplied predicate"
+  let mod3eq = eq `on` \n -> mod n 3
+  assert $ nubByEq mod3eq (l [1, 3, 4, 5, 6]) == l [1, 3, 5]
 
   log "union should produce the union of two lists"
   assert $ union (l [1, 2, 3]) (l [2, 3, 4]) == l [1, 2, 3, 4]
diff --git a/test/Test/Data/List/Lazy.purs b/test/Test/Data/List/Lazy.purs
index e6a7e43..5eef700 100644
--- a/test/Test/Data/List/Lazy.purs
+++ b/test/Test/Data/List/Lazy.purs
@@ -3,10 +3,12 @@ module Test.Data.List.Lazy (testListLazy) where
 import Prelude
 
 import Control.Lazy (defer)
+import Data.Array as Array
 import Data.FoldableWithIndex (foldMapWithIndex, foldlWithIndex, foldrWithIndex)
+import Data.Function (on)
 import Data.FunctorWithIndex (mapWithIndex)
 import Data.Lazy as Z
-import Data.List.Lazy (List, Pattern(..), alterAt, catMaybes, concat, concatMap, cons, delete, deleteAt, deleteBy, drop, dropWhile, elemIndex, elemLastIndex, filter, filterM, findIndex, findLastIndex, foldM, foldMap, foldl, foldr, foldrLazy, fromFoldable, group, groupBy, head, init, insert, insertAt, insertBy, intersect, intersectBy, iterate, last, length, mapMaybe, modifyAt, nil, nub, nubBy, null, partition, range, repeat, replicate, replicateM, reverse, scanlLazy, singleton, slice, snoc, span, stripPrefix, tail, take, takeWhile, transpose, uncons, union, unionBy, unzip, updateAt, zip, zipWith, zipWithA, (!!), (..), (:), (\\))
+import Data.List.Lazy (List, Pattern(..), alterAt, catMaybes, concat, concatMap, cycle, cons, delete, deleteAt, deleteBy, drop, dropWhile, elemIndex, elemLastIndex, filter, filterM, findIndex, findLastIndex, foldM, foldMap, foldl, foldr, foldrLazy, fromFoldable, group, groupBy, head, init, insert, insertAt, insertBy, intersect, intersectBy, iterate, last, length, mapMaybe, modifyAt, nil, nub, nubBy, nubEq, nubByEq, null, partition, range, repeat, replicate, replicateM, reverse, scanlLazy, singleton, slice, snoc, span, stripPrefix, tail, take, takeWhile, transpose, uncons, union, unionBy, unzip, updateAt, zip, zipWith, zipWithA, (!!), (..), (:), (\\))
 import Data.List.Lazy.NonEmpty as NEL
 import Data.Maybe (Maybe(..), isNothing, fromJust)
 import Data.Monoid.Additive (Additive(..))
@@ -102,7 +104,7 @@ testListLazy = do
   log "range should be lazy"
   assert $ head (range 0 100000000) == Just 0
 
-  log "replicate should produce an list containg an item a specified number of times"
+  log "replicate should produce an list containing an item a specified number of times"
   assert $ replicate 3 true == l [true, true, true]
   assert $ replicate 1 "foo" == l ["foo"]
   assert $ replicate 0 "foo" == l []
@@ -328,12 +330,25 @@ testListLazy = do
   log "iterate on nonempty lazy list should apply supplied function correctly"
   assert $ (take 3 $ NEL.toList $ NEL.iterate (_ + 1) 0) == l [0, 1, 2]
 
-  log "nub should remove duplicate elements from the list, keeping the first occurence"
+  log "nub should remove duplicate elements from the list, keeping the first occurrence"
   assert $ nub (l [1, 2, 2, 3, 4, 1]) == l [1, 2, 3, 4]
 
+  log "nub should not consume more of the input list than necessary"
+  assert $ (take 3 $ nub $ cycle $ l [1,2,3]) == l [1,2,3]
+
   log "nubBy should remove duplicate items from the list using a supplied predicate"
-  let nubPred = \x y -> if odd x then false else x == y
-  assert $ nubBy nubPred (l [1, 2, 2, 3, 3, 4, 4, 1]) == l [1, 2, 3, 3, 4, 1]
+  let nubPred = compare `on` Array.length
+  assert $ nubBy nubPred (l [[1],[2],[3,4]]) == l [[1],[3,4]]
+
+  log "nubEq should remove duplicate elements from the list, keeping the first occurrence"
+  assert $ nubEq (l [1, 2, 2, 3, 4, 1]) == l [1, 2, 3, 4]
+
+  log "nubEq should not consume more of the input list than necessary"
+  assert $ (take 3 $ nubEq $ cycle $ l [1,2,3]) == l [1,2,3]
+
+  log "nubByEq should remove duplicate items from the list using a supplied predicate"
+  let mod3eq = eq `on` \n -> mod n 3
+  assert $ nubByEq mod3eq (l [1, 3, 4, 5, 6]) == l [1, 3, 5]
 
   log "union should produce the union of two lists"
   assert $ union (l [1, 2, 3]) (l [2, 3, 4]) == l [1, 2, 3, 4]
diff --git a/test/Test/Data/List/NonEmpty.purs b/test/Test/Data/List/NonEmpty.purs
index 3316456..b12380a 100644
--- a/test/Test/Data/List/NonEmpty.purs
+++ b/test/Test/Data/List/NonEmpty.purs
@@ -2,8 +2,10 @@ module Test.Data.List.NonEmpty (testNonEmptyList) where
 
 import Prelude
 
+import Data.Array as Array
 import Data.Foldable (class Foldable, foldM, foldMap, foldl, length)
 import Data.FoldableWithIndex (foldlWithIndex, foldrWithIndex, foldMapWithIndex)
+import Data.Function (on)
 import Data.List as L
 import Data.List.NonEmpty as NEL
 import Data.Maybe (Maybe(..))
@@ -182,12 +184,19 @@ testNonEmptyList = do
   assert $ partitioned.yes == l [5, 3, 4]
   assert $ partitioned.no == l [1, 2]
 
-  log "nub should remove duplicate elements from the list, keeping the first occurence"
+  log "nub should remove duplicate elements from the list, keeping the first occurrence"
   assert $ NEL.nub (nel 1 [2, 2, 3, 4, 1]) == nel 1 [2, 3, 4]
 
   log "nubBy should remove duplicate items from the list using a supplied predicate"
-  let nubPred = \x y -> if odd x then false else x == y
-  assert $ NEL.nubBy nubPred (nel 1 [2, 2, 3, 3, 4, 4, 1]) == nel 1 [2, 3, 3, 4, 1]
+  let nubPred = compare `on` Array.length
+  assert $ NEL.nubBy nubPred (nel [1] [[2],[3,4]]) == nel [1] [[3,4]]
+
+  log "nubEq should remove duplicate elements from the list, keeping the first occurrence"
+  assert $ NEL.nubEq (nel 1 [2, 2, 3, 4, 1]) == nel 1 [2, 3, 4]
+
+  log "nubByEq should remove duplicate items from the list using a supplied predicate"
+  let mod3eq = eq `on` \n -> mod n 3
+  assert $ NEL.nubByEq mod3eq (nel 1 [3, 4, 5, 6]) == nel 1 [3, 5]
 
   log "union should produce the union of two lists"
   assert $ NEL.union (nel 1 [2, 3]) (nel 2 [3, 4]) == nel 1 [2, 3, 4]