How to merge two hashmaps on Clojure? - clojure

How can I merge two hashmap variables, for example map1 and map2?
I have tried (merge map1 map2), but I got the following exception:
ClassCastException java.util.HashMap cannot be cast to
clojure.lang.IPersistentCollection

well, obviously because java.util.HashMap is not clojure map. You probably get map1 or map2 (or both) executing some java code?
so in this case you should first convert them to clojure maps like this, for example:
(merge (into {} map1) (into {} map2))
this should work.
also read this one: Clojure: working with a java.util.HashMap in an idomatic Clojure fashion

Related

Converting a heavily nested Clojure function to the threaded form

I am trying to convert heavily nested expressions in Clojure.
One example is the following:
(distinct (flatten (map keys (flatten (filter vector? (vals data))))))
The threaded form would be:
(->> data vals (filter vector?) flatten (map keys) flatten distinct)
Is it possible in Clojure to create a function or macro that help me automate getting the threaded form with the nested form as input? Or are there any third-party tools that I can use?
If you're using CIDER, I would recommend clj-refactor. It has refactoring capability for both -> and ->>, as well as a whole bunch of other stuff.

Error when using Integer/parseInt with map in Clojure

I'm learning Clojure and am confused by the following:
(vector "1")
;; returns ["1"]
(map vector '("1" "2" "3"))
;; returns (["1"] ["2"] ["3"])
However:
(Integer/parseInt "1")
;; returns 1
(map Integer/parseInt '("1" "2" "3"))
;; throws error "Unable to find static field: parseInt in class java.lang.Integer"
Instead, I need:
(map #(Integer/parseInt %) '("1" "2" "3"))
;; returns (1 2 3)
If I can use a function like vector with map, why can't I use Integer/parseInt?
You have to wrap it in #() or (fn ...). This is because Integer/parseInt is a Java method and Java methods can't be passed around. They don't implement the IFn interface.
Clojure is built on Java and sometimes this leaks through, and this is one of those cases.
As others have stated, you need to wrap Integer/parseInt in order to convert it from a Java method into a Clojure function:
(map #(Integer/parseInt %) '("1" "2" "3"))
The reason for this is that Clojure functions must implement the IFn interface in order to be passed as arguments into higher order functions such as map.
This is a little bit ugly if you are doing this kind of conversion many times, so I'd recommend wrapping your parse-int function as follows:
(defn parse-int [s] (Integer/parseInt s))
(map parse-int '("1" "2" "3"))
As a final alternative, you may want to use the built-in read-string function - this will return integers in your case but would also work for doubles etc.:
(map read-string '("1" "2" "3"))
Have a look at the Stack Overflow question Convert a sequence of strings to integers (Clojure). The answer says: You have to wrap Integer/parseInt in an anonymous function because Java methods aren't functions.

Converting a list back to a map of maps

I have a function that returns a struct that has two fields, :key :event. The :event field is a map (decomposed Java object retrieved from a cache). In the REPL, I see the return value as a map.
I then apply, (def events (map #(make-event %) (keys events-cache))), applying the make-event function for each key from the cache, and want a map back containing each event map keyed by key.
What I get back is that, but inside a list. So calling any map functions, to search etc., throws an error, clojure.lang.LazySeq cannot be cast to clojure.lang.IFn.
I'm sure I'm thinking about this all wrong, but is there a way to pull the map of maps from the list?
Maybe this is what you want?
(into {} (for [k (keys events-cache)]
[k (make-event k)]))
Your terms are vague, and the error message you post suggests the issue is of a very different sort than the question you're asking. You're likely to get more help if you post some code, and especially a real stacktrace.
But in general, this error message says "You have a lazy seq object that you are trying to call as a function", like:
(let [m1 (map some-function whatever)
m2 (...more stuff...)]
(m1 m2))
If you want to return a two-element list of m1 and m2, rather than calling m1 as a function with m2 as an argument, you want to use the list function:
(list m1 m2)
Assuming you don't care about whatever the values of events-cache were, and that you want to end up with a map of the events-cache keys to the things you generate with make-event, you could do:
(def events
(let [event-keys (keys events-cache)]
(zipmap event-keys (map make-event event-keys))))
I'm not sure why you'd have a cache that includes values, but then not use those values, but that's another question :)
And just for fun:
(into {} (map (juxt identity make-event) event-keys))

Clojure: working with a java.util.HashMap in an idiomatic Clojure fashion

I have a java.util.HashMap object m (a return value from a call to Java code) and I'd like to get a new map with an additional key-value pair.
If m were a Clojure map, I could use:
(assoc m "key" "value")
But trying that on a HashMap gives:
java.lang.ClassCastException: java.util.HashMap cannot be cast to clojure.lang.Associative
No luck with seq either:
(assoc (seq m) "key" "value")
java.lang.ClassCastException: clojure.lang.IteratorSeq cannot be cast to clojure.lang.Associative
The only way I managed to do it was to use HashMap's own put, but that returns void so I have to explicitly return m:
(do (. m put "key" "value") m)
This is not idiomatic Clojure code, plus I'm modifying m instead of creating a new map.
How to work with a HashMap in a more Clojure-ish way?
Clojure makes the java Collections seq-able, so you can directly use the Clojure sequence functions on the java.util.HashMap.
But assoc expects a clojure.lang.Associative so you'll have to first convert the java.util.HashMap to that:
(assoc (zipmap (.keySet m) (.values m)) "key" "value")
Edit: simpler solution:
(assoc (into {} m) "key" "value")
If you're interfacing with Java code, you might have to bite the bullet and do it the Java way, using .put. This is not necessarily a mortal sin; Clojure gives you things like do and . specifically so you can work with Java code easily.
assoc only works on Clojure data structures because a lot of work has gone into making it very cheap to create new (immutable) copies of them with slight alterations. Java HashMaps are not intended to work in the same way. You'd have to keep cloning them every time you make an alteration, which may be expensive.
If you really want to get out of Java mutation-land (e.g. maybe you're keeping these HashMaps around for a long time and don't want Java calls all over the place, or you need to serialize them via print and read, or you want to work with them in a thread-safe way using the Clojure STM) you can convert between Java HashMaps and Clojure hash-maps easily enough, because Clojure data structures implement the right Java interfaces so they can talk to each other.
user> (java.util.HashMap. {:foo :bar})
#<HashMap {:foo=:bar}>
user> (into {} (java.util.HashMap. {:foo :bar}))
{:foo :bar}
If you want a do-like thing that returns the object you're working on once you're done working on it, you can use doto. In fact, a Java HashMap is used as the example in the official documentation for this function, which is another indication that it's not the end of the world if you use Java objects (judiciously).
clojure.core/doto
([x & forms])
Macro
Evaluates x then calls all of the methods and functions with the
value of x supplied at the front of the given arguments. The forms
are evaluated in order. Returns x.
(doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
Some possible strategies:
Limit your mutation and side-effects to a single function if you can. If your function always returns the same value given the same inputs, it can do whatever it wants internally. Sometimes mutating an array or map is the most efficient or easiest way to implement an algorithm. You will still enjoy the benefits of functional programming as long as you don't "leak" side-effects to the rest of the world.
If your objects are going to be around for a while or they need to play nicely with other Clojure code, try to get them into Clojure data structures as soon as you can, and cast them back into Java HashMaps at the last second (when feeding them back to Java).
It's totally OK to use the java hash map in the traditional way.
(do (. m put "key" "value") m)
This is not idiomatic Clojure code, plus I'm modifying m instead of creating a new map.
You are modifying a data structure that really is intended to be modified. Java's hash map lacks the structural sharing that allows Clojures map's to be efficiently copied. The generally idiomatic way of doing this is to use java-interop functions to work with the java structures in the typical java way, or to cleanly convert them into Clojure structures and work with them in the functional Clojure way. Unless of course it makes life easier and results in better code; then all bets are off.
This is some code I wrote using hashmaps when I was trying to compare memory characteristics of the clojure version vs java's (but used from clojure)
(import '(java.util Hashtable))
(defn frequencies2 [coll]
(let [mydict (new Hashtable)]
(reduce (fn [counts x]
(let [y (.toLowerCase x)]
(if (.get mydict y)
(.put mydict y (+ (.get mydict y) 1))
(.put mydict y 1)))) coll) mydict))
This is to take some collection and return how many times each different thing (say a word in a string) is reused.

How do I store Java Methods in a List in Clojure

I want to keep a list of normalizing functions for a text. How do I store .toLowercase?
I was thinking of something like this:
(def normalizing-functions (list remove-punctuations .toLowerCase))
It looks like your making a list of functions to apply to something on a regular basis. the java method is not quite a clojure function in this sense though its really
easy to wrap it up just like you would if you where going to feed it to the map function.
#(. tolowercase %)
Rather than keeping them in a list which you'll have to unpack some way later, it may just be easier to wrap .toLowerCase in a clojure function (edit: using my or Arthur's syntax) and compose it with the functions you're planning to use to normalize your data using comp:
user=> (defn remove-punctuation [st] ...removing puncutation mechanics...)
user=> (defn lower-case [st]
(.toLowerCase st))
user=> ((comp remove-punctuation lower-case) "HELLO THERE!")
"hello there"
user=> (defn normalize-data [data]
((comp remove-punctuation lower-case) data))
The memfn macro will do this in a more readable way.
(def f (memfn toLowerCase))
(f "Hello")
would return "hello". (doc memfn) has the details.