I have a hashmap of data with the key a string description and value an integer weight.
{:a 2 :b 3 ......}
I need to transform the hash into a vector of vectors. Each internal vector contains the map entries.
[[[:a 2][:b 3]...][......]]
each internal vector is built based upon some rules. Ex the sum of all weights should not exceed a certain value
Normally this seems to be a good case for a reduce where a hash is transformed into a vector of vectors of map entries. However I may need to iterate over the hash more than once as I may need to reshuffle the entries between the internal vectors so that all of the vectors sum up to a certain num.
Any suggestions on how the problem should me modelled?
Well, for starters, Clojure maps are already sequences of vectors. So no reduce needed:
=> (for [e {:a 1 :b 2}] e)
([:a 1] [:b 2])
Instead of thinking of it as "iterating," you should take the approach of defining a function that takes your input vectors and returns a new sequence with the adjustment. Recursively call this function until the sum you need is reached.
Related
I'm working Day 6 of Advent of Code 2018, in which I need to store a 2D map of locations, and then do mapping + filtering on them based on their coordinates. I was thinking of storing the locations in a 2D vector, so that the indices of the vectors denote their coordinates, as this is how I would have done it in imperative languages.
However, the majority of the sequence operations only pass the element to the function, so there is no way to access the index of the element from the function passed to e.g. map. Yes, map-indexed exists, but it doesn't feel very clean to have two nested calls to it everytime I operate on the data.
I saw some suggest storing the index, or in this case (x,y) coordinate pair, with the element in the vector: [[[0, 0] "loc1"] [[0, 1] "loc2"] ...]. Would this be better than using nested map-indexed calls, or is there an even cleaner, more idiomatic alternative to storing 2D data and accessing the data with its index?
For this specific problem, the 2D nature of the problem doesn't really matter. So, I'd suggest storing the points as a vector of maps like so:
{:x x
:y y
:nearest-point :A}
and locations like:
{:x x
:y y
:name :A}
for example. For each point, loop over the locations and save the closest one. Then, throw out the infinite ones:
(remove #(is-it-infinite? %) points)
Then
(group-by :nearest-point points)
and count the size of each group to get the final answer.
You could use matrices:
(require '[clojure.core.matrix :as m])
(def A (m/matrix [[1 4 56] [5 2 8] [35 1 677]]))
(m/emap-indexed (fn [[x y] v] (prn [x y v])) A)
Vector and map can act as function to get its elements from key
([1 2 3] 2) ;=> 3
({:a 1 :b 2} :a) ;=> 1
but why I can not do this for list?
('(1 2 3) 2)
;clojure.lang.PersistentList cannot be cast to clojure.lang.IFn(java.lang.ClassCastException)
I think the error message is pretty descriptive in this case. Persistent list doesn't implement IFn, therefore cannot act as function. This is Clojure design choice and the reason may be that List datastructure is not designed for random access (getting element by index), because complexity of this operation is O(n), which is much worse than vector's O(log(n)).
On "Programming Clojure", there is an example using get function on a vector:
(get [:a :b :c] 1)
-> :b
I called (doc get) and it looks like get function takes hashmap as argument but not vector, so I wander if vector is some kind of hashmap. I remember a hashmap can take an index integer, and return value matching that index, so I did this to see if vector can do same thing:
([1 2 3 4] 1)
-> 2
It did return value 2, which is at index 1 in [1 2 3 4].
Does this mean a vector is a hashmap, whose keys-value pair is index-value pair?
No, the underlying implementation is different.
That being said, since logically vectors do map indices to elements, they are associative structures in Clojure and can be used with get, contains? and assoc (though for assoc only indices from 0 to 1 past the end of the vector can be used). They cannot be used with dissoc though -- that's a "real map" operation.
Also, vectors act differently to maps when used as functions: calling a map as a function is equivalent to using it with get, while calling a vector is equivalent to using nth. The difference is that nth throws an exception on index-out-of-bounds (as well as arguments which could not possibly be indices, such as negative numbers or non-numbers), whereas get returns nil.
Why does (group-by identity (range 1 50)) return results like
{32 [32], 1 [1], 33 [33], 2 [2], 34 [34], 3 [3], 35 [35]...
Is it multi-threading related? Is there any way around it?
...and does it break it's contract?
Returns a map of the elements of coll keyed by the result of f on each element. The value at each key will be a vector of the corresponding elements, in the order they appeared in coll.
Try entering (type (group-by identity (range 1 50))) in your REPL. You can see that the result is actually a hash map (of class clojure.lang.PersistentHashMap). This means that it's unordered: in principle the REPL could output the printed map literal in any order of key/value pairs.
The actual reason why it's printed the way it's printed has to do with Clojure's implementation of a hash map -- in terms of data structures, it's actually a wide tree where each node can have up to 32 children (hence the initial 32 in your output; recall that Clojure vectors and maps are often cited to have lookup cost of O(log32N)). This blog article has a good summary.
And no, it doesn't violate the contract of group-by. The contract only specifies the ordering of the map's values' elements, not the ordering of the map per se.
I would like to compare two copies of parts of a ref to see if they have changed. How can I get a sha1 of a map and any sub leaves?
Depending on exactly what you want to do, you may find just using the normal Java hashCode() via the "hash" function is simpler than trying to use SHA:
(hash {:a "hoho" :b "hehe"})
=> 2025831869
(hash {:a "hoho" :b "hihi"})
=> 2025836181
This is enough in most cases to determine if two maps are different.
Note that neither SHA or any other hashcode guarantee equality when two objects have the same hash - many objects can potentially have the same hash. As a consequence, if the hash is the same you will still have to check whether the two objects are equal in value
Also, be aware that computing hashes is more expensive than a simple comparison using =. So it only makes sense to use a hashing technique if you are able to store the hash value and re-use it for many comparisons.
are you sure you actually want something as low-level as that? Identity in clojure, at least wrt values, is kinda built in:
user> (= {:a 1, :b {:c 2}} (hash-map :b {:c 2} :a 1))
true