Putting key-values into map conditionally, what are the concise ways?
What are the concise/ elegant ways to put into a map key-value pairs for which the corresponding conditions are true?
That is to translate
[condition1 condition2 ...] [key1 val1 key2 val2 ...]
or
[condition1 condit开发者_开发百科ion2 ...] [key1 key2 ...] [val1 val2 ...]
or
[condition1 key1 val1 condition2 key2 val2...]
into
{key-for-true-condition1 val-for-true-condition1, key-for-true-condition2 val-for-true-condition2...}
I think to use "reduce" with "if" in its lambda but interested in more concise/ beautiful/ elegant/ idiomatic ways.
(into {} (for [[c k v] (partition 3 coll) :when c]
[k v]))
Based on the 'for'-Version from Kintaro but a little shorter.
To be honest IMO, the version with see comment from nickik below.reduce
and if
are already the most elegant and idiomatic
(def coll [true :a "v1" false :b "v2" true :c "v3"])
(reduce (fn [a [c k v]] (if c (assoc a k v) a)) {} (partition 3 coll))
Here is a version using the for comprehension for the third case:
(apply array-map (flatten (for [[c k v] (partition 3 coll) :when c]
[k v])))
Edit:
For the second case you convert it to the third case by doing:
(def c [true false true])
(def k [:a :b :c])
(def v ["v1" "v2" "v3"])
(def coll (interleave c k v))
But I think the map
version from nickik is better here.
I would first think about it as how to be best map your functional operations over a stream:
- Group condition/key/value into a chunk
- Filter chunks where the condition is not true
- Drop the conditions
- Flatten the chunks
- Create a map from the result
Which looks like:
(def coll [true :a "v1" false :b "v2" true :c "v3"])
(apply hash-map
(flatten
(map #(drop 1 %)
(filter #(first %)
(partition 3 coll)))))
Or if you're feeling thready:
(->> coll
(partition 3)
(filter #(first %))
(map #(drop 1 %))
flatten
(apply hash-map))
I'm not sure this is elegant or concise, but I think it's easy to read. Note that if you frequently deal with data in this shape, you may find that steps like (partition 3 coll) or (first %) might be useful reusable functions in their own right leading to something like:
(defn condition-group [coll] (partition 3 coll))
(defn condition [group] (first group))
(defn but-condition [group] (drop 1 group))
(defn kv-map [kv-pairs] (apply hash-map (flatten kv-pairs)))
(->> coll
condition-group
(filter condition)
(map but-condition)
kv-map)
(def coll [true :key1 "value1" false :key2 "value2" true :key3 "value3"])
(defn testpair [[cond key val]]
(when cond
{key val}))
(apply merge (map testpair (partition 3 coll)))
=> {:key3 "value3", :key1 "value1"}
This would be one way but if you want other combinations of condition key and value you have to change the code. You didn't mention witch one would be best.
Edit: Because its the first on your list
(def conditions [true false true] )
(def keyval [:key1 "value1" :key2 "value2" :key3 "value3"])
(defn testpair [cond [key val]]
(when cond
{key val}))
(apply merge (map testpair conditions (partition 2 keyval)))
Because its fun :)
(def conditions [true false true] )
(def keys [:key1 :key2 :key3])
(def vals ["value1" "value1" "value3"])
(defn testpair [cond key val]
(when cond
{key val}))
(apply merge (map testpair conditions keys vals))
精彩评论