Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Created March 30, 2021 13:21
Show Gist options
  • Select an option

  • Save ericnormand/c2a1dd5f9dd04cd0dd9919d464e6fadf to your computer and use it in GitHub Desktop.

Select an option

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/

@steffan-westcott

steffan-westcott commented Mar 30, 2021 •

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

@mchampine

mchampine commented Mar 30, 2021 •

Copy link
Copy Markdown

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

steffan-westcott commented Mar 30, 2021 •

Copy link
Copy Markdown

@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
Copy Markdown

@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
Copy Markdown

@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
Copy Markdown
(defn uniques
  [coll]
  (or (keys (filter #(= (last %) 1) 
                    (frequencies coll)))
      '()))

@vpetruchok

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

@burnall

burnall commented Mar 30, 2021

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

@nwjsmith

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

@miner

miner commented Mar 30, 2021 •

Copy link
Copy Markdown

Inspired by @steffan-westcott

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

@steffan-westcott

steffan-westcott commented Mar 30, 2021 •

Copy link
Copy Markdown

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

miner commented Mar 30, 2021

Copy link
Copy Markdown

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

miner commented Mar 30, 2021 •

Copy link
Copy Markdown

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

mchampine commented Mar 30, 2021 •

Copy link
Copy Markdown

@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

zackteo commented Mar 30, 2021

Copy link
Copy Markdown

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
Copy Markdown
(defn uniques [xs]
  (let [frq (frequencies xs)]
    (filter #(= 2 (get frq %)) xs)))

@stevenpkent

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

@sztamas

sztamas commented Mar 31, 2021

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

@filippocostalli

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

@sim-f

sim-f commented Apr 5, 2021 •

Copy link
Copy Markdown
(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

vmpj commented Apr 5, 2021

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

@fahadbuddy

fahadbuddy commented Apr 6, 2021 •

Copy link
Copy Markdown
(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
Copy Markdown

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

burnall commented Apr 6, 2021 •

Copy link
Copy Markdown

@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
Copy Markdown

@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