I have a one-dimensional vector, a vector of indices to update within the vector, and a value which should be associated with each of these indices.
I'm new to Clojure, and imagine that there might be a more idiomatic way to write the routine that I ended up with:
(defn update-indices-with-value [v indices value]
(loop [my-v v
my-indices indices
my-value value]
(if (empty? my-indices)
my-v
(recur (assoc my-v (peek my-indices) my-value)
(pop my-indices)
my-value))))
I know that assoc can be used to update multiple keys or indices within an associative collection, but I couldn't figure out the syntactic magic to use assoc with an arbitrary list of keys or indices.
Use reduce:
(defn assoc-all
[v ks value]
(reduce #(assoc %1 %2 value) v ks))
Example:
(assoc-all [1 2 3 4] [0 1] 2)
;; => [2 2 3 4]
Alternatively, create the key/value pairs and use apply:
(defn assoc-all
[v ks value]
(->> (interleave ks (repeat value))
(apply assoc v)))
If assoc was using transients internally this might actually be more efficient than the reduce version. Since it isn't, the lazy sequence overhead is probably eating it all up.
So, finally, a transient version:
(defn assoc-all
[v ks value]
(persistent!
(reduce
#(assoc! %1 %2 value)
(transient v)
ks)))
Related
This is similar to Clojure get map key by value
However, there is one difference. How would you do the same thing if hm is like
{1 ["bar" "choco"]}
The idea being to get 1 (the key) where the first element if the value list is "bar"? Please feel free to close/merge this question if some other question answers it.
I tried something like this, but it doesn't work.
(def hm {:foo ["bar", "choco"]})
(keep #(when (= ((nth val 0) %) "bar")
(key %))
hm)
You can filter the map and return the first element of the first item in the resulting sequence:
(ffirst (filter (fn [[k [v & _]]] (= "bar" v)) hm))
you can destructure the vector value to access the second and/or third elements e.g.
(ffirst (filter (fn [[k [f s t & _]]] (= "choco" s))
{:foo ["bar", "choco"]}))
past the first few elements you will probably find nth more readable.
Another way to do it using some:
(some (fn [[k [v & _]]] (when (= "bar" v) k)) hm)
Your example was pretty close to working, with some minor changes:
(keep #(when (= (nth (val %) 0) "bar")
(key %))
hm)
keep and some are similar, but some only returns one result.
in addition to all the above (correct) answers, you could also want to reindex your map to desired form, especially if the search operation is called quite frequently and the the initial map is rather big, this would allow you to decrease the search complexity from linear to constant:
(defn map-invert+ [kfn vfn data]
(reduce (fn [acc entry] (assoc acc (kfn entry) (vfn entry)))
{} data))
user> (def data
{1 ["bar" "choco"]
2 ["some" "thing"]})
#'user/data
user> (def inverted (map-invert+ (comp first val) key data))
#'user/inverted
user> inverted
;;=> {"bar" 1, "some" 2}
user> (inverted "bar")
;;=> 1
This is a scenario I encountered many times, yet didn't find an idiomatic approach for it...
Suppose one would like to use a self-defined self-pred function to filter a seq. This self-pred function returns nil for unwanted elements, and useful information for wanted elements. It is desirable to keep the evaluated self-pred values for these wanted elements.
My general solution is:
;; self-pred is a pred function which returns valuable info
;; in general, they are unique and can be used as key
(let [new-seq (filter self-pred aseq)]
(zipmap (map self-pred new-seq) new-seq))
Basically, it is to call self-pred twice on all wanted elements. I feel it is so ugly...
Wonder if there is any better ways. Much appreciated for any input!
In these scenarios you can use keep, but you have to change your "predicate" function to return the full information you need, or nil, for each item.
For example:
(keep (fn [item]
(when-let [tested (some-test item)]
(assoc item :test-output tested))) aseq)
i use this kind of snippet:
(keep #(some->> % self-pred (vector %)) data)
like this:
user> (keep #(some->> % rseq (vector %)) [[1 2] [] [3 4]])
;;=> ([[1 2] (2 1)] [[3 4] (4 3)])
or if you like more verbose result:
user> (keep #(some->> % rseq (hash-map :data % :result)) [[1 2] [] [3 4]])
;;=> ({:result (2 1), :data [1 2]} {:result (4 3), :data [3 4]})
I wouldn't bother with keep, but would just use plain map & filter like so:
(def data (range 6))
(def my-pred odd?)
(defn zip [& colls] (apply map vector colls)) ; like Python zip
(defn filter-with-pred
[vals pred]
(filter #(first %)
(zip (map pred vals) vals)))
(println (filter-with-pred data my-pred))
with result:
([true 1] [true 3] [true 5])
If self-pred guarantees no duplicate key creation for differing values then I'd reach for reduce (since assoc the same key twice will override the original key value pair):
(reduce #(if-let [k (self-pred %2)]
(assoc %1 k %2)
%1)
{}
aseq)
Else we can use group-by to drive a similar result:
(dissoc (group-by self-pred aseq) nil)
Although not the same since the values will be in vectors: {k1 [v1 ..], k2 [..], ..}. but this guarantees all values are kept.
Given:
{:o {:i1 1
:i2 {:ii1 4}}}
I'd like to iterate over the keys of the map in "absolute" form from the root as a vector. So I'd like:
{
[:o :i1] 1
[:o :i2 :ii1] 4
}
As the result. Basically only get the leaf nodes.
A version that I think is rather nicer, using for instead of mapcat:
(defn flatten-keys [m]
(if (not (map? m))
{[] m}
(into {}
(for [[k v] m
[ks v'] (flatten-keys v)]
[(cons k ks) v']))))
The function is naturally recursive, and the most convenient base case for a non-map is "this one value, with no keyseq leading to it". For a map, you can just call flatten-keys on each value in the map, and prepend its key to each keyseq of the resulting map.
Looks like this is basically a flatten of the nested keys. This also seems to be a 4clojure problem.
A flatten-map search on github yield many results.
One example implementation:
(defn flatten-map
"Flattens the keys of a nested into a map of depth one but
with the keys turned into vectors (the paths into the original
nested map)."
[s]
(let [combine-map (fn [k s] (for [[x y] s] {[k x] y}))]
(loop [result {}, coll s]
(if (empty? coll)
result
(let [[i j] (first coll)]
(recur (into result (combine-map i j)) (rest coll)))))))
Example
(flatten-map {:OUT
{:x 5
:x/A 21
:x/B 33
:y/A 24}})
=> {[:OUT :x] 5, [:OUT :x/A] 21, [:OUT :x/B] 33, [:OUT :y/A] 24}
An even more general version from Christoph Grand:
(defn flatten-map
"Take a nested map (or a nested collection of key-value pairs) and returns a
sequence of key-value pairs where keys are replaced by the result of calling
(reduce f pk path) where path is the path to this key through the nested
maps."
([f kvs] (flatten-map f nil kvs))
([f pk kvs]
(mapcat (fn [[k v]]
(if (map? v)
(flatten-map f (f pk k) v)
[[(f pk k) v]])) kvs)))
Example:
(flatten-map conj [] {:OUT
{:x 5
:x/A 21
:x/B 33
:y/A 24}})
=> ([[:OUT :x] 5] [[:OUT :x/A] 21] [[:OUT :x/B] 33] [[:OUT :y/A] 24])
I have the following variable
(def a [[1 2] [3 4] [5 6]])
and want to return
[[1 3 5][2 4 6]]
and if input is
[[1 2] [3 4] [5 6] [7 8 9]] then the required result is
[[1 3 5 7] [2 4 6 8] [9]]
How to do it in clojure?
(persistent!
(reduce
(fn [acc e]
(reduce-kv
(fn [acc2 i2 e2]
(assoc! acc2 i2 ((fnil conj []) (get acc2 i2) e2)))
acc
e))
(transient [])
[[1 2 3] [:a :b] [\a] [111] [200 300 400 500]]))
;;=> [[1 :a \a 111 200] [2 :b 300] [3 400] [500]]
An empty vector can be updated via the update-in fn at the 0th index, a non-empty vector can be, additionally, updated at the index immediately following the last value.
The reduction here is about passing the outer accumulator to the inner reducing function, updating it accordingly, and then returning it back to the outer reducing function, which in turn will pass again to the inner rf for processing the next element.
EDIT: Updated to fastest version.
I like ifett's implementation, though it seems weird to use reduce-kv to build a vector that could be easily build with map/mapv.
So, here is how I would've done it:
(defn transpose [v]
(mapv (fn [ind]
(mapv #(get % ind)
(filter #(contains? % ind) v)))
(->> (map count v)
(apply max)
range)))
(->> (range)
(map (fn [i]
(->> a
(filter #(contains? % i))
(map #(nth % i)))))
(take-while seq))
Notice that this algorithm creates a lazy seq of lazy seqs so you that you will only pay for the transformations you really consume. If you insist on creating vectors instead, wrap the forms in vec at the necessary places - or if you are using Clojurescript or don't mind a Clojure 1.7 alpha use transducers to create vectors eagerly without paying for laziness or immutability:
(into []
(comp
(map (fn [i]
(into [] (comp (filter #(contains? % i))
(map #(nth % i)))
a)))
(take-while seq))
(range))
I find this easy to understand:
(defn nth-column [matrix n]
(for [row matrix] (nth row n)))
(defn transpose [matrix]
(for [column (range (count (first matrix)))]
(nth-column matrix column)))
(transpose a)
=> ((1 3 5) (2 4 6))
nth-column is a list comprehension generating a sequence from the nth element of each sequence (of rows).
Then transpose-matrix is simply iterating over the columns creating a sequence element for each, consisting of (nth-column matrix column) i.e. the sequence of elements for that column.
(map
(partial filter identity) ;;remove nil in each sub-list
(take-while
#(some identity %) ;;stop on all nil sub-list
(for [i (range)]
(map #(get % i) a)))) ;; get returns nil on missing values
Use get to have nil on missing values, iterate (for) on an infinite range, stop on all nil sub-list, remove nil from sub-lists. Add vector constructor before first map and in it's function (first argument) if you really need vectors.
EDIT: please leave a comment if you think this is not useful. We can all learn from mistakes.
I'm working my way through 4clojure and I'm stuck on Problem 156 (Map Defaults).
I can't figure out why the function bellow doesn't return a flat map
((fn [d k] (for [i k :let [r {}]]
(conj r [i d])))
[:a :b] [:foo :bar])
Current result is ({:foo [:a :b]} {:bar [:a :b]})
But I expected {:foo [:a :b], :bar [:a :b]}
Inside for, r is created anew in every iteration, gets populated with [i d] and gets yielded as an element of the lazy sequence. As a result, you obtain this sequence whose elements are small one-entry maps.
What you need is reduce. It loops over a sequence updating the accumulator using a function you provide:
(defn fun1 [d k]
(reduce
(fn [acc i] (conj acc [i d]))
{}
k))
It starts from an empty map, and for every element i in k it calls the lambda, which adds an entry to the map (passed to the lambda as acc). The result is one big map with all these entries.
Alternatively, you could just generate the key/value pairs with your for expression, and then use the into function to shove them all in a map:
((fn [d k] (into {} (for [i k] [i d])))
[:a :b] [:foo :bar])
; => {:foo [:a :b], :bar [:a :b]}
For those coming here looking for a flatmap function in Clojure, check out mapcat:
Returns the result of applying concat to the result of applying map to
f and colls.