Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Last active June 26, 2020 20:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericnormand/235696a7f7cca803f772a2d1bd1b90c3 to your computer and use it in GitHub Desktop.
Save ericnormand/235696a7f7cca803f772a2d1bd1b90c3 to your computer and use it in GitHub Desktop.

unique values

Let's keep it easy this week as we get back into it.

Write a function called uniques that takes a sequence of values. That sequence is going to have zero or more unique values. The rest will repeat at least once. Your job is to return the unique values in the same order as they appear in the argument sequence.

Examples

(uniques [1 2 3 4 5 6 1 2 3 5 6]) ;=> (4)
(uniques [:a :b :c :c]) ;=> (:a :b)
(uniques [1 2 3 1 2 3]) ;=> ()

Thanks to this site for the challenge idea where it is considered Medium level in Python.

Email submissions to eric@purelyfunctional.tv before June 21, 2020. You can discuss the submissions in the comments below.

(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn uniques
[vals]
(let [freqs (frequencies vals)
result (vec (keys (t/submap-by-vals freqs #{1} :missing-ok)))]
result))
(dotest
(is= (uniques [1 2 3 4 5 6 1 2 3 5 6]) [4])
(is= (uniques [:a :b :c :c]) [:a :b])
(is= (uniques [1 2 3 1 2 3]) []))
(defn uniques [xs]
(->> (get (group-by second (frequencies xs)) 1)
(map first)))
(ns uniques)
(require '[clojure.test :as test])
(defn uniques [coll]
(filter (fn [elt-e]
(= 1 (count
(filter (fn [elt-i]
(= elt-i elt-e))
coll))))
(reverse (set coll))))
(test/deftest uniques-test
(test/is (= '(4) (uniques [1 2 3 4 5 6 1 2 3 5 6])))
(test/is (= '(:a :b) (uniques [:a :b :c :c])))
(test/is (= '() (uniques [1 2 3 1 2 3]))))
(test/run-tests 'uniques)
(defn uniques [xs]
(->> (group-by identity xs)
(vals)
(filter (comp (partial = 1) (partial count)))
(mapcat identity)))
(ns purelyfun.382.core)
(defn uniques
[values]
(map first (filter #(= (count %) 1) (vals (group-by identity values)))))
(ns purelyfun.382.test
(:require [clojure.test :refer :all]
[purelyfun.382.core :refer :all]))
(deftest test-unique
(is (= (uniques [1 2 3 4 5 6 1 2 3 5 6]) '(4)))
(is (= (uniques [:a :b :c :c]) '(:a :b)))
(is (= (uniques [1 2 3 1 2 3]) '()))
)
(comment
(clojure.test/run-tests 'purelyfun.382.test)
(defn rt []
(let [tns 'purelyfun.382.test]
(use tns :reload-all)
(clojure.test/test-ns tns))
)
)
(defn single-in-coll? [n coll] (= 1 (count (filter #(= % n) coll))))
(defn uniques [coll] (filter #(single-in-coll? % coll) coll))
(defn ordered-frequencies [seq] (reduce #(assoc %1 %2 (inc (get %1 %2 0))) (array-map) seq))
(defn uniques [seq]
(map first
(filter
#((partial = 1) (second %))
(ordered-frequencies seq))))
(ns functional-tv-puzzles.-2020.uniques-382)
;; Hand-rolled without frequencies. Two-pass, including ordering
(defn ordering [xs]
(->> xs
(into {} (map-indexed #(vector %2 %1)))))
(defn uniques [xs]
(let [o (ordering xs)]
(loop [seen #{}
kept (sorted-set-by #(< (o %) (o %2)))
[x & more :as coll] xs]
(cond
(empty? coll)
(apply list kept)
(seen x)
(recur seen (disj kept x) more)
:else
(recur (conj seen x) (conj kept x) more)))))
(defn uniques [coll]
(sort (vec (set coll))) )
(defn uniques
"Returns a seq containing the values that appear exactly once in `s`.
The order in which the values appear in `s` is preserved."
[s]
(->> s
(filter #(= 1
((frequencies s) %)))))
;; Note to self: when ordering is involved, test with at
;; least 33 elements. Data transformation pipelines often
;; include tranforming to maps (e.g. frequencies, zipmap).
;; Coincidentally, for small maps, Clojure seems to preserve
;; order up to and including 8 elements; ClojureScript does
;; this up to and including 32 elements.
(assert (= (uniques (concat (range 33) [1 3 5]))
[0 2 4 6 7 8 9 10 11 12 13 14 15 16 17 18
19 20 21 22 23 24 25 26 27 28 29 30 31 32]))
(defn uniques [xs]
(filter (comp #(= 1 %) (frequencies xs)) xs))
(defn uniques [l]
(for [e l :when (= 1 (count (filter #{e} l)))] e))
(defn uniques [coll]
(->> coll
(group-by identity)
(filter (fn [[_ [_ & rest]]] (empty? rest)))
(map first)))
(defn uniques [coll]
(let [freqs (frequencies coll)]
(filter #(= 1 (get freqs %)) coll)))
(defn uniques
[xs]
(let [unique-items (->> xs
frequencies
(filter #(= 1 (val %)))
keys
set)]
(if (some nil? unique-items)
(filter #(or (nil? %)
(unique-items %)) xs )
(filter unique-items xs ))))
(deftest uniques-test
(testing "uniques"
(is (= '(:a :b) (uniques [:a :b :c :c])))
(is (= '(4) (uniques [1 2 3 4 5 6 1 2 3 5 6])))
(is (= '() (uniques [1 2 3 1 2 3])))
(is (= '(nil 1) (uniques [nil 2 3 1 2 3])))
(is (= '() (uniques [nil nil ])))))
(defn uniques [xs]
(let [counts (frequencies xs)
dups (->> (filter (fn [[x cnt]] (> cnt 1)) counts)
(map first)
set)]
(remove #(contains? dups %) xs)))
(defn uniques
"Given a sequence of values return, in the same order in which they
appear, those among them that are unique e.g. [1 2 1 3] ==> [2 3]."
[v]
(let [same (group-by identity v)]
(reduce (fn [res k]
(if (= 1 (count (get same k)))
(conj res k)
res))
[]
v)))
(defn uniques [xs]
(let [freqs (frequencies xs)]
(filter #(= 1 (freqs %)) xs)))
(defn uniques [xs]
(let [freq (frequencies xs)]
(for [x xs
:when (= 1 (get freq x))]
x)))
@KingCode
Copy link

KingCode commented Jun 15, 2020

I am inspired by @souenzzo's (comp #{1} ...). My solution is more convoluted by iterating on the frequencies instead of the coll. Two variants:

(defn ordering [xs]
  (->> xs (map-indexed #(vector %2 %))
       (into {})))

(defn key-when [pred]
  (fn [[k v]]
    (when (pred v)
      k)))

(defn uniques [xs]
  (->> xs 
       frequencies
       (keep (key-when #{1}))
       (sort-by (ordering xs))))

(defn uniques-2 [xs]
  (let [o (ordering xs)]
    (->> xs
         frequencies
         seq flatten
         (apply sorted-map-by #(compare (o %) (o %2)))
         (keep (key-when #{1})))))

@burnall
Copy link

burnall commented Jun 15, 2020

It is a rare case when it is optimal to use -> pipeline with collections.

(defn uniques [coll]
  (-> coll
      (frequencies)
      (#(fn [x] (= 1 (% x))))
      (filter coll)))

@duzunov
Copy link

duzunov commented Jun 15, 2020

Here is my submission:

(defn single-in-coll? [n coll]
  (= 1 (count (filter #(= % n) coll)))) 
(defn uniques [coll]
  (filter #(single-in-coll? % coll) coll))

@zugnush
Copy link

zugnush commented Jun 16, 2020

I think from the spec that maybe a unique nil should be reported

(defn uniques
  [xs]
  (let [unique-items (->> xs
                          frequencies
                          (filter #(= 1 (val %)))
                          keys
                          set)]
    (if (some nil? unique-items)
      (filter #(or (nil? %)
                   (unique-items %)) xs )
      (filter unique-items xs ))))

(deftest uniques-test
  (testing "uniques"
    (is (= '(:a :b) (uniques [:a :b :c :c])))
    (is (= '(4) (uniques [1 2 3 4 5 6 1 2 3 5 6])))
    (is (= '() (uniques [1 2 3 1 2 3])))
    (is (= '(nil 1) (uniques [nil 2 3 1 2 3])))
    (is (= '() (uniques [nil nil ])))))

@tychobrailleur
Copy link

tychobrailleur commented Jun 17, 2020

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

@burnall
Copy link

burnall commented Jun 18, 2020

@tychobrailleur This condition "unique values in the same order as they appear in the argument sequence" is not fulfilled, unfortunately. It would be nice to use into for java.util.LinkedHashSet which keeps insertion order, but it does not work.

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