Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Created March 30, 2021 13:21
Show Gist options
  • Save ericnormand/c2a1dd5f9dd04cd0dd9919d464e6fadf to your computer and use it in GitHub Desktop.
Save ericnormand/c2a1dd5f9dd04cd0dd9919d464e6fadf to your computer and use it in GitHub Desktop.
420 PurelyFunctional.tv Newsletter

Unique elements

There's a function in Clojure called distinct that removes duplicates from a sequence. Your task is to write a function called uniques that removes elements that appear twice.

Examples

(uniques []) ;=> ()
(uniques [1 2 3]) ;=> (1 2 3)
(uniques [1 1 2 3]) ;=> (2 3)
(uniques [1 2 3 1 2 3]) ;=> ()
(uniques [1 2 3 2]) ;=> (1 3)

Thanks to this site for the challenge idea where it is considered Medium in Python. The problem has been modified from the original.

Please submit your solutions as comments on this gist.

To subscribe: https://purelyfunctional.tv/newsletter/

@miner
Copy link

miner commented Mar 30, 2021

Inspired by @steffan-westcott

(defn uniques [coll]
  (let [freqs (frequencies coll)]
    (sequence (filter #(= 1 (freqs %)))   coll)))

@steffan-westcott
Copy link

steffan-westcott commented Mar 30, 2021

It's interesting to note that maps are not order preserving, meaning insertion order is not always the same as its seq order. My observations show this becomes apparent for maps with over 8 entries. As a consequence, several answers given so far have this behaviour:

(uniques (range 8))
=> (0 1 2 3 4 5 6 7)
(uniques (range 9))
=> (0 7 1 4 6 3 2 5 8)

If you really want to preserve insertion order, you could use a library such as Linked

@miner
Copy link

miner commented Mar 30, 2021

Small maps are PersistentArrayMap and larger ones are PersistentHashMap. You shouldn't count on any ordering unless you explicitly use sorted-map (PersistentTreeMap). However, you can depend on the (seq m) using the same unspecified ordering as (keys m) and (vals m), which is sometimes useful.

@miner
Copy link

miner commented Mar 30, 2021

Originally, I thought order didn't matter. On second thought, maybe you're right. The original specification mentioned distinct and that maintains order. Back to the drawing board.

@mchampine
Copy link

mchampine commented Mar 30, 2021

@steffan-westcott

You may want to think about preserving the order of the sequence.

Even more ambiguity!

  1. This challenge doesn't specify whether or not order is preserved. (and my function passes all the example tests).
  2. A literal interpretation of "remove elements that appear twice" would leave untouched all elements appearing 1 or 3+ times in the result! I.e.:
(defn rem-el-occ-twice [s] (remove #(= 2 ((frequencies s) %)) s))

(rem-el-occ-twice [1 2 2 3 3 3])
;; => (1 3 3 3)

@zackteo
Copy link

zackteo commented Mar 30, 2021

Could probably make this more concise if I spend more time but this is what I got

(defn uniques [s]
  (->> s
       sort
       (partition-by identity)
       (keep #(if (= (count %) 1) %))
       flatten
       ))

@diavoletto76
Copy link

(defn uniques [xs]
  (let [frq (frequencies xs)]
    (filter #(= 2 (get frq %)) xs)))

@stevenpkent
Copy link

(defn uniques
  [coll]
  (->> (frequencies coll) 
       (filter #(not= (val %) 2)) 
       (map first)))

@sztamas
Copy link

sztamas commented Mar 31, 2021

(defn uniques [coll]
  (let [freqs   (frequencies coll)
        unique? (comp zero? dec freqs)]
    (filter unique? coll)))

@filippocostalli
Copy link

(defn uniques [c]
  (->> c
       (frequencies)
       (filter (fn [[k v]] (< v 2)))
       (map (fn [[k v]] k))))

@sim-f
Copy link

sim-f commented Apr 5, 2021

(defn has-two [freq-map e]
  (if (not= (get freq-map e)
         2)
    true
    false))

(defn uniques [input]
  (let [freq-map (frequencies input)]
    (filter #(has-two freq-map %) input)))

@vmpj
Copy link

vmpj commented Apr 5, 2021

(defn uniques [s]
(->> s
  frequencies
  (filter #(= 1 (second %)))
  (map first)))

@fahadbuddy
Copy link

fahadbuddy commented Apr 6, 2021

(defn uniques [xs]
  (let [freqs (frequencies xs)]
    (filter (comp #{1} freqs) xs)))

I am trying to understand this solution. What does this mean?

#{1} freqs

a hashset is being applied to a map? Could someone please help elaborate?

@pwojnowski
Copy link

This is simple, fast, preserves the order, and wins code-golf (I guess), but doesn't work in ClojureScript 😉

(defn uniques [xs]
    (seq (java.util.LinkedHashSet. xs)))

@burnall
Copy link

burnall commented Apr 6, 2021

@fahadbuddy #{1} is a set.
(your-set key) means getting a value from the set, i.e. key or nil if it is not in the set.

E.g.

(map #{1} [1 2 3]) ; => (1 nil nil)

@mchampine
Copy link

@farhadbuddy Note the use of “comp”. The set #{1} gets applied not to freqs but rather to the result of applying freqs to an element of xs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment