Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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/

@steffan-westcott
Copy link

steffan-westcott commented Mar 30, 2021

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

@mchampine
Copy link

mchampine commented Mar 30, 2021

Wording is ambiguous. Is this challenge the same as https://gist.github.com/ericnormand/235696a7f7cca803f772a2d1bd1b90c3 ? Or should the behavior be to remove only elements that appear exactly twice??

(defn rem-el-occ-twice [l]
  (map first (remove #( = 2 (val %)) (frequencies l))))

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

@steffan-westcott
Copy link

steffan-westcott commented Mar 30, 2021

@mchampine I initially had the same question, but then I took my cue from the name uniques to mean removing all elements which appear at least twice, i.e. retain elements which appear exactly once. When phrased like that, I think my answer is a fairly direct implementation, which chimes with the theme of this week's newsletter!

@mchampine
Copy link

mchampine commented Mar 30, 2021

@steffan-westcott I agree that's probably the intent, in which case my answer is in the earlier gist - so I figured I'd implement the other behavior for this one. :)

@steffan-westcott
Copy link

steffan-westcott commented Mar 30, 2021

@mchampine You may want to think about preserving the order of the sequence. Using your answer, I get:

(rem-el-occ-twice (range 10))
=> (0 7 1 4 6 3 2 9 5 8)

@arthurulacerda
Copy link

arthurulacerda commented Mar 30, 2021

(defn uniques
  [coll]
  (or (keys (filter #(= (last %) 1) 
                    (frequencies coll)))
      '()))

@vpetruchok
Copy link

vpetruchok commented Mar 30, 2021

(defn uniques [xs]
  (let [suited (->> xs
                    (frequencies)
                    (filter #(< (val %) 2))
                    (map key)
                    set) ]
    (filter #(contains? suited %) xs)))

@burnall
Copy link

burnall commented Mar 30, 2021

(defn uniques [xs]
  (->> xs
       (filter (comp (partial = 1) 
                     (frequencies xs)))))

@nwjsmith
Copy link

nwjsmith commented Mar 30, 2021

(defn uniques
  [coll]
  (->> (frequencies coll)
       (filter #(= 1 (val %)))
       (map key)))

@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

diavoletto76 commented Mar 30, 2021

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

@stevenpkent
Copy link

stevenpkent commented Mar 30, 2021

(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

filippocostalli commented Mar 31, 2021

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

@simbiotiqu
Copy link

simbiotiqu 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

pwojnowski commented Apr 6, 2021

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

mchampine commented Apr 6, 2021

@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