4clojure 63 Group a Sequence

My first attempt at writing up one of my 4clojure solutions. Problem 63 “Group a Sequence” requires you to re-implement group-by. As always looking at the source code is cheating :-)

Given a function f and a sequence s, write a function which returns a map. The keys should be the values of f applied to each item in s. The value at each key should be a vector of corresponding items in the order they appear in s.

(= (__ #(> % 5) [1 3 6 8]) {false [1 3], true [6 8]})

Here’s how I worked it out in the REPL, warts and all…

;; map seems a good start here

((map #(> % 5) [1 3 6 8])
;; (false false true true)

;; so I’m getting the values of fn here, I want the inputs too
;; I can’t think of a clever way to do this, I’ll just use for and list

(defn foo [f xs] (for [x xs :let [y (f x)]] (list y x)))
(foo #(> % 5) [1 3 6 8])
;; ((false 1) (false 3) (true 6) (true 8))

;; the for loop can be tightend up, I don’t need the :let

(defn foo [f xs] (for [x xs] (list (f x) x)))
(foo #(> % 5) [1 3 6 8])
;; ((false 1) (false 3) (true 6) (true 8))

;; I know I want my results as maps, so use a map instead

(defn foo [f xs] (for [x xs] {(f x) x}))
(foo #(> % 5) [1 3 6 8])
;; ({false 1} {false 3} {true 6} {true 8})

;; now I’m stuck; how do I moosh the results together?
;; I read thru all the map change fn’s in the clj cheatsheet
;; hmmm, merge-with looks promising

(defn foo [f xs] (merge-with concat (for [x xs] {(f x) x})))
(foo #(> % 5) [1 3 6 8])
;; ({false 1} {false 3} {true 6} {true 8})

;; WTF? same results. Re-RTFM on merge-with. Well, I’m going to
;; need vectors in my results to be able to concat them…

(defn foo [f xs] (merge-with concat (for [x xs] {(f x) [x]})))
(foo #(> % 5) [1 3 6 8])
;; ({false [1]} {false [3]} {true [6]} {true [8]})

;; WTF? still not mooshing together. Uh duh, fn signature takes
;; “maps” not a list. Use the “list stripper” – apply!

(defn foo [f xs] (apply merge-with concat (for [x xs] {(f x) [x]})))
(foo #(> % 5) [1 3 6 8])
;; {true (6 8), false (1 3)}

;; ha, sweetness and light! Remove the defn and submit:

(fn [f xs] (apply merge-with concat (for [x xs] {(f x) [x]})))

;; look at other’s solutions. Dacquiri as usual has a more elegant
;; solution, with a reader macro. What’s his golf handicap?!?!

#(apply merge-with concat (for [x %2] {(% x) [x]}))

Mooshing is an advanced programming technique, that can only be used after years of study and practice…

Tags:


Share This


 


Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>