How to sum all values in a hashmap? - clojure

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

Related

Plotting two lists in Clojure

I have two lists. For e.g.: list A is [1 2 3 2 2 1] and list B is [1.2 2.2 1 1 1 1]. I want to have the unique numbers of list A on the x-axis and sum of the corresponding entries in list B. For eg: For the above example, I want to plot {(1,2.2),(2,4.2),(3,1)} as a histogram ( not a scatter plot).
My requirement involves two steps.
First to sum values in list B for each unique value in list A
Plotting these sums against the corresponding values in list A as a histogram.
Can you please help me.
Edit:
Here is my attempt, based on the little I could understand from reading other answers on SO:
(def A [1 2 3 2 1])
(def B [1.2 2.3 2 1 1])
(for [x (distinct A)] (map first
(filter #(= (second %) x)
(map-indexed vector A))))
;; This gives the indices for each unique element in A
;; In this case, it gives ((0 4) (1 3) (2))
I am unable to figure out how to find how to get corresponding sum from list B. I tried the following but it does not work.
(apply nth B (map first
(filter #(= (second %) 1)
(map-indexed vector A))) )
;; In this case, it gives on the first element i.e. 1.2
As you can see, I am new to Clojure and functional programming languages. Can you please point me towards some examples which have solved similar problems?
Thanks in advance.
Edit:
Final solution for the first task:
(for [x (distinct A)] (reduce + 0.0 (map #(nth B %) (map first
(filter #(= (second %) x)
(map-indexed vector A))) ) ) )
;; This gives me the correct output (2.2 3.3 2.0)
P.S: I did not understand this concept of using (map #(nth B%)... I just stumbled onto it from other examples.
For the first task, I guess this way is a bit simpler:
(def A [1 2 3 2 2 1])
(def B [1.2 2.2 1 1 1 1])
(def C
(reduce (partial merge-with +)
(map hash-map A B))) ; Vector of key-values [{1 1.2} {2 2.2} ...]
; {1 2.2, 2 4.2, 3 1}
For the second task, there are many chart library options out there. I picked up clj-xchart as an example:
(require '[com.hypirion.clj-xchart :as c])
(let [x-values (keys C)
min-x (apply min x-values)
max-x (apply max x-values)]
(c/view
(c/category-chart
{"C" C}
{:title "Example"
:legend {:visible? false}
:x-axis {:order (range min-x max-x)}
:theme :ggplot2})))
And the final plot:

Clojure manually find nth element in a sequence

I am a newbie to clojure (and functional programming for that matter) and I was trying to do some basic problems. I was trying to find the nth element in a sequence without recursion.
so something like
(my-nth '(1 2 3 4) 2) => 3
I had a hard time looping through the list and returning when i found the nth element. I tried a bunch of different ways and the code that I ended up with is
(defn sdsu-nth
[input-list n]
(loop [cnt n tmp-list input-list]
(if (zero? cnt)
(first tmp-list)
(recur (dec cnt) (pop tmp-list)))))
This gives me an exception which says "cant pop from empty list"
I dont need code, but if someone could point me in the right direction it would really help!
You are using the function pop, which has different behavior for different data structures.
user> (pop '(0 1 2 3 4))
(1 2 3 4)
user> (pop [0 1 2 3 4])
[0 1 2 3]
user> (pop (map identity '(0 1 2 3 4)))
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentStack clojure.lang.RT.pop (RT.java:640)
Furthermore, you are mixing calls to pop with calls to first. If iterating, use peek/pop or first/rest as pairs, mixing the two can lead to unexpected results. first / rest are the lowest common denominator, if you want to generalize over various sequential types, use those, and they will coerce the sequence to work if they can.
user> (first "hello")
\h
user> (first #{0 1 2 3 4})
0
user> (first {:a 0 :b 1 :c 2})
[:c 2]
With your function, replacing pop with rest, we get the expected results:
user> (defn sdsu-nth
[input-list n]
(loop [cnt n tmp-list input-list]
(if (zero? cnt)
(first tmp-list)
(recur (dec cnt) (rest tmp-list)))))
#'user/sdsu-nth
user> (sdsu-nth (map identity '(0 1 2 3 4)) 2)
2
user> (sdsu-nth [0 1 2 3 4] 2)
2
user> (sdsu-nth '(0 1 2 3 4) 2)
2
user> (sdsu-nth "01234" 2)
\2
given a list as list_nums, take up to n + 1 then from that return the last element which is nth.
(fn [list_nums n] (last (take (inc n) list_nums)))
and alternatively:
#(last (take (inc %2) %1))
proof:
(= (#(last (take (inc %2) %1)) '(4 5 6 7) 2) 6) ;; => true
What you would really want to do is use the built-in nth function as it does exactly what you're asking:
http://clojuredocs.org/clojure_core/clojure.core/nth
However, since you're learning this is still a good exercise. Your code actually works for me. Make sure you're giving it a list and not a vector -- pop does something different with vectors (it returns the vector without the last item rather than the first -- see here).
Your code works fine for lists if supplied index is not equal or greater then length of sequence (you've implemented zero indexed nth). You get this error when tmp-list gets empty before your cnt gets to the zero.
It does not work so well with vectors:
user> (sdsu-nth [1 2 3 4] 2)
;; => 1
user> (sdsu-nth [10 2 3 4] 2)
;; => 10
it seems to return 0 element for every supplied index. As noisesmith noticed it happens because pop works differently for vectors because of their internal structure. For vectors pop will remove elements form the end, and then first returns first value of any vector.
How to fix: use rest instead of pop, to remove differences in behavior of your function when applied to lists and vectors.
(fn [xs n]
(if (= n 0)
(first xs)
(recur (rest xs) (dec n))))
One more way that I thought of doing this and making it truly non recursive (ie without for/recur) is
(defn sdsu-nth
[input-list n]
(if (zero? (count input-list))
(throw (Exception. "IndexOutOfBoundsException"))
(if (>= n (count input-list))
(throw (Exception. "IndexOutOfBoundsException"))
(if (neg? n)
(throw (Exception. "IndexOutOfBoundsException"))
(last (take (+ n 1) input-list))))))

How to change few lists inside single hashmap?

I wonder what is the idiomatic way of doing complicated data structures changes. Here is a hashmap that contains lists, i want to take one of those list and move some items to the other one:
input:
{ :a (1 2 3) :b (4 5) }
output:
{ :a (2 3) :b (4 5 1) }
"first element of :a is added as last to :b"
In practice I need such structure to represent game state like:
{ :first_player { :deck (2 3 4 5) :hand (6 1) :discard () }
:second_player { :deck (1 8 9 10) :hand (3) :discard (1 7) }
:board { :first_player_side (1 3) :second_player_side (7 9) }}
As u can see i will need to move cards ids from different lists to different lists in various hashmaps (play from hand to board, move from board to discard pile etc). I just wonder how to make it in simple/readable way.
Thanks for answers.
Clojure has an update-in function, designed for doing complicated data structures changes:
(defn magic [{:keys [a] :as m}]
(-> m
(update-in [:a] rest)
(update-in [:b] concat (take 1 a))))
Or more general solution:
(defn move-els [m from to numel]
(let [els (take numel (get m from))]
(-> m
(update-in [from] (partial drop numel))
(update-in [to] concat els))))
Try it:
=> (move-els { :a '(1 2 3) :c "foo" :b '(4 5) } :a :b 2)
{:a (3), :c "foo", :b (4 5 1 2)}
Are you looking for map destructuring?
(defn frob [{:keys [a b]}]
{:a (rest a) :b (conj b (first a))})
This doesn't do exactly what you want, of course, because that wouldn't be much fun.
See http://blog.jayfields.com/2010/07/clojure-destructuring.html for a good quick overview of restructuring.

Clojure transients - assoc! causing exception

Here is the function I'm trying to run...
(defn mongean [cards times]
(let [_cards (transient cards)]
(loop [i 0 c (get cards i) _count (count cards) _current (/ _count 2)]
(assoc! _cards _current c)
(if ((rem i 2) = 0)
(def _newcur (- _current (inc i)))
(def _newcur (+ _current (inc i))))
(if (<= i _count)
(recur (inc i) (get cards i) _count _newcur )))
(persistent! _cards)))
It's resulting in this Exception...
Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.ITransientAssociative
Being new to clojure, I'd also appreciate any constructive criticism of my approach above. The goal is to take a List, and return a re-ordered list.
I assume that you are trying to implement the Mongean shuffle. Your approach is very imperative and you should try to use a more functional approach.
This would be a possible implementation, were we calculate the final order of the cards (as per Wikipedia formula) and then we use the built-in replace function to do the mapping:
(defn mongean [cards]
(let [num-cards (count cards)
final-order (concat (reverse (range 1 num-cards 2)) (range 0 num-cards 2))]
(replace cards final-order)))
user> (mongean [1 2 3 4 5 6 7 8])
(8 6 4 2 1 3 5 7)
How do you call that function? It looks like you're passing a set, so that its transient version will also be a set and hence can't be used with any of the assoc functions, as they work on associative data structures and vectors:
user=> (assoc #{} :a 1)
ClassCastException clojure.lang.PersistentHashSet cannot be cast to clojure.lang.Associative clojure.lang.RT.assoc (RT.java:691)
user=> (assoc! (transient #{}) :a 1)
ClassCastException clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.ITransientAssociative clojure.core/assoc! (core.clj:2959)
; the following works as it uses maps and vectors
user=> (assoc {} :a 1)
{:a 1}
user=> (assoc! (transient {}) :a 1)
#<TransientArrayMap clojure.lang.PersistentArrayMap$TransientArrayMap#65cd1dff>
user=> (assoc [] 0 :a)
[:a]
Now, let's try to discuss the code itself. It's a bit hard to follow your code and try to understand what the goal really is without some more hints on what you want to achieve, but as general comments:
you have a times input parameter you don't use at all
you are supposed to use the result of a transient mutation, not assume that the transient will mutate in place
avoid transients if you can, they're only meant as a performance optimization
the binding _current (/ _count 2) is probably not what you want, as (/ 5 2) really returns 5/2 and it seems that you want to use it as a position in the result
constants like _count don't need to be part of the loop binding, you can use the outer let so that you don't have to pass them at each and every iteration
use let instead of def for naming things inside a function
(if ((rem 1 2) = 0)) is definitely not what you want
Now, leaving aside the shuffling algorithm, if you need to rearrange a sequence you might just produce a sequence of new positions, map them with the original cards to produce pairs of [position card] and finally reduce them by placing the card at the new position, using the original sequence as the seed:
(defn generate [coll] ; counts down from (count coll) to 0, change to
; implement your shuffling algorithm
(range (dec (count coll)) -1 -1))
(defn mongean [cards times]
(let [positions (generate cards) ; get the new positions
assemble (fn [dest [pos card]] ; assoc the card at the wanted position
(assoc dest pos card))]
(reduce assemble cards (map vector positions cards))))
If you simply want to shuffle:
(defn mongean [cards times] (shuffle cards))

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))