yazz.com
yazz.com

Reputation: 58786

How can I sort a clojure set of maps?

I have a set of maps something like this:

#{
  {:name "a" :value "b" ... more stuff here}
  {:name "b" :value "b" ... more stuff here}
  {:name "b" :value "b" ... more stuff here}
  {:name "a" :value "b" ... more stuff here}
  {:name "c" :value "b" ... more stuff here}
  {:name "a" :value "b" ... more stuff here}
}

: and I want to get to an ordered list, much like sql order-by name:

[
  {:name "a" :value "b" ... more stuff here}
  {:name "a" :value "b" ... more stuff here}
  {:name "a" :value "b" ... more stuff here}
  {:name "b" :value "b" ... more stuff here}
  {:name "b" :value "b" ... more stuff here}
  {:name "c" :value "b" ... more stuff here}
]

: how can I do this?

Upvotes: 19

Views: 6878

Answers (5)

haijin
haijin

Reputation: 948

I believe the snippet from the joy of clojure is the neatest.

(def plays [{:band "Burial",     :plays 979,  :loved 9}
           {:band "Eno",        :plays 2333, :loved 15}
           {:band "Bill Evans", :plays 979,  :loved 9}
           {:band "Magma",      :plays 2665, :loved 31}])

(def sort-by-loved-ratio (partial sort-by #(/ (:plays %) (:loved %))))

Upvotes: 3

MayDaniel
MayDaniel

Reputation: 1484

(def set-of-maps #{{:name "d"}, {:name "b"}, {:name "a"}})

-> clojure.core/sort-by

(sort-by :name set-of-maps)

; => ({:name "a", :value "b"} {:name "c", :value "b"} {:name "d", :value "b"})

Upvotes: 5

Arthur Ulfeldt
Arthur Ulfeldt

Reputation: 91534

sort-by is a great answer, and makes the code a lot better in the simple cases where it works. Additionally the sort function can take a function to extract the comparason key from each map incase you need to do some processing on each item. In this example i use a sort function that extracts each name and then does a string compare on them.

(sort #(compare (:name %1) (:name %2)) data)
=>  ({:name "a", :value "b"} {:name "b", :value "b"} {:name "c", :value "b"})

this is useful if your collections had different names to be compared:

(sort #(compare (:value %1) (:name %2)) data)
=> ({:name "a", :value "b"} {:name "c", :value "b"} {:name "b", :value "b"})

the compare function is a better version of java's .compareto() because it properly handles nil and compares clojure collections properly. is is basically a short cut for using the . opperator in most cases

(sort #(. (:name %1) (compareTo (:name %2))) data)
=> ({:name "a", :value "b"} {:name "b", :value "b"} {:name "c", :value "b"})

Upvotes: 7

amalloy
amalloy

Reputation: 91857

sort-by is what you want, but please post snippets that are actually valid code; I wasted a fair bit of time trying to figure out a problem that wound up being because #{{:name "a" :value "b"} {:name "a" :value "b"}} makes the reader barf.

Upvotes: 4

Leonel
Leonel

Reputation: 29189

Function sort-by is what you're looking for:

(def s
  #{
    {:name "d" :value "b" }
    {:name "b" :value "b" }
    {:name "c" :value "b" }
    })
(sort-by :name s)

Upvotes: 34

Related Questions