Reduce/Apply mismatch - clojure

I'm using Clojure 1.8 and I expected reduce and apply to be output-wise equivalent for this particular example.
user=> (apply max-key val {:a 2 :bb 1})
[:a 2]
user=> (reduce max-key val {:a 2 :bb 1})
[:bb 1]
They look like they are not, could anyone explain why? Thanks

apply prepends the arguments to the call of max-key. reduce - on the other hand - reduces over {:a 2 :bb 1}, calling max-key with two arguments. The val is treated as the initial value of the accumulator in the reduce.
A reduce form that is equivalent to your apply would be:
(reduce #(max-key val %1 %2) {:a 2 :bb 1})

(reduce max-key val {:a 2 :bb 1}) uses max-key as the accumulator and val as the initial value. It effectively expands into:
(max-key (max-key val [:a 2]) [:bb 1]))
(max-key val [:a 2]) is [:a 2] and (max-key [:a 2] [:bb 1])

Related

into vs. partition

This makes sense:
user=> (into {} [[:a 1] [:b 2]])
{:a 1, :b 2}
But why does this generate an error?
user=> (into {} (partition 2 [:a 1 :b 2]))
ClassCastException clojure.lang.Keyword cannot be cast to java.util.Map$Entry clojure.lang.ATransientMap.conj (ATransientMap.java:44)
Just to be sure:
user=> (partition 2 [:a 1 :b 2])
((:a 1) (:b 2))
Does into have a problem with lazy sequences? If so, why?
Beyond an explanation of why this doesn't work, what is the recommended way to conj a sequence of key-value pairs like [:a 1 :b 2] into a map? (apply conj doesn't seem to work, either.)
You can apply the sequence to assoc:
(apply assoc {:foo 1} [:a 1 :b 2])
=> {:foo 1, :a 1, :b 2}
Does into have a problem with lazy sequences? If so, why?
No, into is commonly used with lazily evaluated sequences. This is lazy, but each key/value tuple is a vector, which is why it works when into is reducing the pairs into the map:
(into {} (map vector (range 3) (repeat :x)))
=> {0 :x, 1 :x, 2 :x}
This doesn't work because the key/value pairs are lists:
(into {} (map list (range 3) (repeat :x)))
So the difference isn't laziness; it's due to into using reduce using conj on the map, which only works with vector key/value pairs (or MapEntrys):
(conj {} [:a 1]) ;; ok
(conj {} (MapEntry. :a 1)) ;; ok
(conj {} '(:a 1)) ;; not ok
Update: assoc wrapper for applying empty/nil sequences as suggested in comments:
(defn assoc*
([m] m)
([m k v & kvs]
(apply assoc m k v kvs)))
The recommended way – (assuming the seq arg is non-empty, as pointed out by the OP) – would be
Clojure 1.9.0
user=> (apply assoc {} [:a 1 :b 2])
{:a 1, :b 2}
The version with partition doesn't work because the blocks that partition returns are seqs and those are not treated as map entries when conj'd on to a map the way vectors and actual map entries are.
E.g. (into {} (map vec) (partition 2 [:a 1 :b 2])) would work because here the pairs get converted to vectors before conjing.
Still the approach with assoc is preferable unless there's some particular circumstance that makes into convenient (like, say, if you have a bunch of transducers that you want to use for preprocessing your partition-generated pairs etc.).
Clojure treats a 2-vec such as [:a 1] as equivalent to a MapEntry, doing what amounts to "automatic type conversion". I try to avoid this and always be explicit.
(first {:a 1}) => <#clojure.lang.MapEntry [:a 1]>
(conj {:a 1} [:b 2]) => <#clojure.lang.PersistentArrayMap {:a 1, :b 2}>
So we see that a MapEntry prints like a vector but has a different type (just like a Clojure seq prints like a list but has a different type). seq converts a Clojure map into a sequence of MapEntry's, and first gets us the first one (most Clojure functions call (seq ...) on any input collections before any other processing).
Notice that conj does the inverse type conversion, treating the vector [:b 2] as if it were a MapEntry. However, conj won't perform automatic type conversion for a list or a seq:
(throws? (conj {:a 1} '(:b 2)))
(throws? (into {:a 1} '(:b 2)))
into has the same problem since it is basically just (reduce conj <1st-arg> <2nd-seq>).
The other answers already have 3 ways that work:
(assoc {} :b 2) => {:b 2}
(conj {} [:b 2]) => {:b 2}
(into {} [[:a 1] [:b 2]]) => {:a 1, :b 2}
However, I would avoid those and stick to either hash-map or sorted-map, both of which avoid the problem of empty input seqs:
(apply hash-map []) => {} ; works for empty input seq
(apply hash-map [:a 1 :b 2]) => {:b 2, :a 1}
If your input sequence is a list of pairs, flatten is sometimes helpful:
(apply sorted-map (flatten [[:a 1] [:b 2]])) => {:a 1, :b 2}
(apply hash-map (flatten '((:a 1) (:b 2)))) => {:a 1, :b 2}
P.S.
Please be note that these are not the same:
java.util.Map$Entry (listed in jdk docs as "Map.Entry")
clojure.lang.MapEntry
P.P.S
If you already have a map and want to merge in a (possibly empty) sequence of key-value pairs, just use a combination of into and hash-map:
(into {:a 1} (apply hash-map [])) => {:a 1}
(into {:a 1} (apply hash-map [:b 2])) => {:a 1, :b 2}

Understanding what appears to be an example of destructuring in clojure

The following code:
(into {} [[:a 1][:b 2][:c 3][:d 4][:e 5]])
...produces a map(?) of keyword / value pairs. I don't quite understand the significance of the double square brackets and I am assuming it is an example of destructuring?
Thanks,
~Caitlin
It's not a destructuring, it's just an example of using into core function.
into is a function used to conjoin two collection by repeatedly adding elements from the second collection to the first one with conj function.
So, (into {} [[:a 1][:b 2]]) is just a synonym for
(-> {} (conj [:a 1]) (conj [:b 2]))
This answer is a supplement to Leonid's. One can think of a Clojure map as a collection of "map entries", key/value pairs. These are sometimes printed so that they look like 2-element vectors, though they are not 2-element vectors. Nevertheless, if you want to convert something into a map using into, it makes sense that you should pass the data that will turn into map entries in the form of 2-element vectors.
=> (def foo {:a 1 :b 2 :c 3})
#'/foo
=> (find foo :b)
[:b 2]
=> (class (find foo :b))
clojure.lang.MapEntry
=> (map identity foo)
([:c 3] [:b 2] [:a 1])
=> (map class (map identity foo))
(clojure.lang.MapEntry clojure.lang.MapEntry clojure.lang.MapEntry)
=> (list [:c 3] [:b 2] [:a 1])
([:c 3] [:b 2] [:a 1])
=> (map class (list [:c 3] [:b 2] [:a 1]))
(clojure.lang.PersistentVector clojure.lang.PersistentVector clojure.lang.PersistentVector)

What does Clojure's zip-map do?

I am new at Clojure and I needed help with this function. If you could please tell me what this function does and how it works I would be really thankfull.
(defn zip-map
[k v]
(into{} (map vec (partition 2 (interleave k v)))))
Example of usage:
(zip-map [:a :b :c] [1 2 3]) ;=> {:a 1, :b 2, :c 3}
And from the inside out:
(interleave [:a :b :c] [1 2 3]) ;=> (:a 1 :b 2 :c 3)
(partition 2 '(:a 1 :b 2 :c 3)) ;=> ((:a 1) (:b 2) (:c 3))
(map vec '((:a 1) (:b 2) (:c 3))) ;=> ([:a 1] [:b 2] [:c 3])
(into {} '([:a 1] [:b 2] [:c 3])) ;=> {:a 1, :b 2, :c 3}
The function is more complicated hence harder to understand than it need be. It could be written thus:
(defn zip-map [ks vs]
(into {} (map vector ks vs)))
when
(zip-map [:a :b :c] [1 2 3])
;{:a 1, :b 2, :c 3}
as before.
The function imitates the standard zipmap, which you can find explained, complete with source code, in the official docs or ClojureDocs, which also gives examples. Both these sites help you to pick your way through the Clojure vocabulary.
As is often the case, the standard function is faster though more complex than the simple one-liner above.

conj-ing a list of values to a map value in Clojure?

What is the idiomatic way of conj-ing a list of values to a map value?
This is the result I want, but the anonymous function looks kind of ugly imo. Is there a better way?
> (update-in {:x #{}} [:x] #(apply conj % '(1 2)))
{:x #{1 2}}
The anonymous function is unnecessary
(update-in {:x #{}} [:x] conj 1 2)
;=> {:x #{1 2}}
(update-in {:x #{}} [:x] into [1 2])
;=> {:x #{1 2}}
You should not have to know whether the map contains? the key that you are conjing values to. Adapting your example ...
(update-in {} [:x] #(apply conj % '(1 2)))
;{:x (2 1)}
... not what you want.
The following
(defn assocs [m k coll]
(assoc m k (into (get m k #{}) coll)))
... supplies an empty-set value if no entry for the key exists.
(assocs {} :x [1 2])
;{:x #{1 2}}
(assocs {:x #{2}} :x [1 2])
;{:x #{1 2}}
You'll find similar code in clojure.algo.graph, for example here. (Warning: the graph type only functions in one of the algorithms and otherwise just gets in the way.)

Convert an array of tuples into a hash-map in Clojure

I have an array of tuples, where each tuple is a 2 tuple with a key and a value. What would be the cleanest way to convert this array of tuples into a hash-map?
user=> (into {} [[:a 1] [:b 2]])
{:a 1, :b 2}
A map is a sequence of MapEntry elements. Each MapEntry is a vector of a key and value. The tuples in the question are already in the form of a MapEntry, which makes things convenient. (That's also why the into solution is a good one.)
user=> (reduce conj {} [[:a 1] [:b 2]])
{:b 2, :a 1}
Assuming that "tupel" means "two-elememt array":
(reduce
(fn [m tupel]
(assoc m
(aget tupel 0)
(aget tupel 1)))
{}
array-of-tupels)
user=> (def a [[:a 4] [:b 6]])
user=> (apply hash-map (flatten a))
{:a 4, :b 6}