Get first x number of elements from a hashmap in clojure - clojure

How does one retrieve the first x key value pairs from a sorted clojure map of 2x key value pairs

Simply use take on a sorted-map:
(def a (sorted-map 3 :a 2 :b 1 :c))
(take 2 a) ;; ([1 :c] [2 :b])

Related

adding keys to a sequence of vectors in a vector and converting them to hash-maps

Given
[["foo" "bar" 2] ["biz" "baf" 3]]
how do I get
[{:a "foo" :b "bar" :num 2} {:a "biz" :b "baf" :num 3}]?
In reality my vector has hundreds of vectors that need to have keys added and be converted to hash-maps.
What leetwinski said, or:
(def input [["foo" "bar" 2]["biz" "baf" 3]])
(mapv (fn [[a b num]]
{:a a
:b b
:num num}) input)
If you need to convert a lot of data, maybe mapv is not the best option because it will keep the whole vector in memory at once. Normal map which creates a lazy seq, or a transducer might be better in that case.
A general solution:
(defn vectors->maps
"takes a vector of vectors containing values and a vector of keys
and returns a vector of maps such that each value at index n in the value
vector is paired with each key at index n in the keys vector
ex: (vectors->maps [["foo" "bar" 2] ["biz" "baf" 3]], [:a :b :num])
=> [{:a "foo", :b "bar", :num 2} {:a "biz", :b "baf", :num 3}]"
[vectors keys]
(mapv (partial zipmap keys) vectors))
Exercise for the reader: writing a spec for this function and generating tests for it to ferret out any edge cases

How to sum all values in a hashmap?

In Clojure, I have a map like this:
(def data {:a 1 :b 2 :c 3})
I want to sum all the elements and get 6 as a result. I know I should probably use reduce, but I'm at a loss at how to do it correctly.
There are two easy ways you can do this.
With reduce
(reduce + (vals data))
Or with apply
(apply + (vals data))
They are equivalent for associative functions.
I'd suggest that apply is more idiomatic, because + is already implemented via reduce.
That is, if we calculate (+ 1 2 3), the result is 6. So it's natural to ask why (+ (vals data)) isn't sufficient.
The result of (vals data) is the list (1 2 3). + sees this as a single argument and just returns that value... oops.
(+ (vals data))
=> (1 2 3)
apply works by essentially unpacking the list.
You are correct, you should reduce here. vals will get you the values you want to add up, then just reduce them over the addition function.
user=> (def data {:a 1 :b 2 :c 3})
#'user/data
user=> (vals data)
(3 2 1)
user=> (reduce + (vals data))
6

How to convert map to a sequence?

Answers to this question explain how to convert maps, sequences, etc. to various sequences and collections, but do not say how to convert a map to a sequence of alternating keys and values. Here is one way:
(apply concat {:a 1 :b 2})
=> (:b 2 :a 1)
Some alternatives that one might naively think would produce the same result, don't, including passing the map to vec, vector, seq, sequence, into [], into (), and flatten. (Sometimes it's easier to try it than to think it through.)
Is there anything simpler than apply concat?
You can also do
(mapcat identity {:a 1 :b 2})
or
(mapcat seq {:a 1 :b 2})
As #noisesmith gently hints below, the following answer is seductive but wrong: left as a warning to other unwary souls! Counterexample:
((comp flatten seq) {[1 2] [3 4], 5 [6 7]})
; (1 2 3 4 5 6 7)
(comp flatten seq) does the job:
((comp flatten seq) {1 2, 3 4})
; (1 2 3 4)
But flatten on its own doesn't:
(flatten {1 2, 3 4})
; ()
I'm surprised it doesn't work, and in that case it should return nil, not ().
None of the others you mention: vec, vector ... , does anything to the individual [key value] pairs that the map presents itself as a sequence of.

Convert map of list into list of maps (i.e. rows to colums)

I have the following data structure in Clojure
{:a [1 2 3]
:b [4 5 6]
:c [7 8 9]}
And I'd like to convert it into something like
[{:a 1 :b 4 :c 7}
{:a 2 :b 5 :c 8}
{:a 3 :b 6 :c 9}]
At the moment I'm kinda stumped as to how to do this.
In Clojure you can never guarantee the order of keys in maps after transformations. They're indexed by key, not by order.
Vectors are, however. And with get-in you can do a lookup on position with a vector of coordinates .
=> (def mat
[[1 2 3]
[4 5 6]
[7 8 9]])
=> (defn transpose
[m]
(apply mapv vector m))
=> (get-in (transpose mat) [1 2])
8
Got it:
(defn transpose-lists [x]
(map (fn [m] (zipmap (keys x) m)) (apply map vector (vals x))))
Unfortunately it doesn't preserve order of the keys.
If anyone has a better solution then of course I'd like to hear it!

return sequence of clojure map values in a specific order

If I have a map, for example,
(def mymap { :b 1 :a 2 :d 3 :e 4 :f 5})
I can use vals to get a sequence of all of the values
(vals mymap)
;=> (1 2 3 4 5)
how do I get the sequence of values in my own custom order, to get for example
;=> (4 2 3 1 5)
what I eventually want to do is serialize the values to a string, doing something like this
(defn serialize [m sep] (apply str (concat (interpose sep (vals m)) ["\n"])))
(this example function was taken from the "serialize an input-map into string" post)
but I need to specify the order of the vals.
Maps are functions of their keys, so you can do this:
(map mymap [:e :a :d :b :f])
=> (4 2 3 1 5)
For 1.3 you can use the priority-map,
http://clojure.github.com/clojure-contrib/branch-master/priority-map-api.html
or you can use sort-by,
(let [m { 1 8 3 6 5 4 7 2}]
(println (map first (sort-by second m)))
(println (map first (sort-by first m))))
(7 5 3 1)
(1 3 5 7)
In case you want to sort the map depending on the keys, and then get the values,
Brian has an example on how to do this using sort-by
Or you can just implement your own sort comparator
I don't want to sort (although thanks for the sorting tips), I just want to specify the order
when I pull the values from the map.
I found a way to do it - destructuring the map.
(let [{:keys [a b d e f]} mymap]
(println e a d b f))