If we think about what we're doing here is a stateful filter, then maybe we
could leverage a few more core Clojure functions:


(defn distinct-by [f coll]
  (let [seen (atom #{})]
    (filter (fn [itm]
               (let [m (f itm)]
                  (when-not (@seen m)
                    (swap! seen conj m))))
             coll)))

Now it's true, we're using a atom and a bit of mutability where none
existed before, but personally I think the intent is a bit clearer in this
code. What we're saying is "filter out all results we've seen before". If
this was production code I would probably replace the atom with a
`volatile!` but that's just for (small) performance reasons.


On Sat, Jul 22, 2017 at 7:36 AM, Rob Nikander <rob.nikan...@gmail.com>
wrote:

> Hi,
>
> Here's a function and a simple use of it. It works, but the code may not
> be good Clojure. I'm wondering how it might be better.
>
> (defn distinct-by
>   "Returns a sequence with no repeats of (f item).
>   A set is built up internally as the sequence is consumed, so don't use
> it on
>   an infinite sequence or you will run out of memory."
>   ([f coll]
>     (letfn [(get-more [seen input-seq]
>                (if (not (empty? input-seq))
>                  (let [x (first input-seq)
>                        fx (f x)]
>                    (if (contains? seen fx)
>                      (lazy-seq (get-more seen (rest input-seq)))
>                      (lazy-seq (cons x (get-more (conj seen fx) (rest
> input-seq))))))))]
>        (get-more #{} (seq coll)))))
>
> (def xs (list {:n 1, :a 'a} {:n 2, :a 'b} {:n 3, :a 'a} {:n 4, :a 'c} {:n
> 5, :a 'b}))
>
> (distinct-by :a xs)
> => ({:n 1, :a a} {:n 2, :a b} {:n 4, :a c})
>
> Rob
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>



-- 
“One of the main causes of the fall of the Roman Empire was that–lacking
zero–they had no way to indicate successful termination of their C
programs.”
(Robert Firth)

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to