I would like to convert a NamedTuple to a Dict in Julia. Say I have the following NamedTuple:
julia> namedTuple = (a=1, b=2, c=3)
(a = 1, b = 2, c = 3)
I want the following:
julia> Dict(zip(keys(namedTuple), namedTuple))
Dict{Symbol, Int64} with 3 entries:
:a => 1
:b => 2
:c => 3
This works, however I would've hoped for a somewhat simpler solution - something like
julia> Dict(namedTuple)
ERROR: ArgumentError: Dict(kv): kv needs to be an iterator of tuples or pairs
would have been nice. Is there such a solution?
The simplest way to get an iterator of keys and values for any key-value collection is pairs:
julia> Dict(pairs(namedTuple))
Dict{Symbol, Int64} with 3 entries:
:a => 1
:b => 2
:c => 3
Related
Looking at the example:
(into [] (select-keys {:a 1 :b 2 :c 3} [:c :b])) => [[:c 3] [:b 2]]
Is it guaranteed that returned result will preserve order declared in second parameter of select-key?
select-keys returns a map which are unorderd, so you can't rely on it. Small maps are represented as arrays which do maintain order but this is broken as the size increases e.g.
(def m {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9 :j 10 :k 11 :l 12 :m 13})
(into [] (select-keys m [:a :b :c :d :e :f :g :h :i :j :k]))
=> [[:e 5] [:k 11] [:g 7] [:c 3] [:j 10] [:h 8] [:b 2] [:d 4] [:f 6] [:i 9] [:a 1]]
It's not a reliable function to preserve orders, as well as keys and vals which do not preserve the order of how you defined the map.
The most reliable way is to use a loop / recur if you want to output an ordered vector of kv (or a reduce as well).
If you want ordered values only, you can use juxt.
I would add that pragmatically hashmaps are not meant to represent ordered data.
If the ordering is a fairly simple one, you can easily sort the map by using sorted-map-by:
(def m (select-keys {:a 1 :b 2 :c 3 :d 4} [:d :b]))
=> {:d 4, :b 2}
(def sm (sorted-map-by compare))
(into sm m)
=> {:b 2, :d 4}
(assoc *1 :c 1234)
=> {:b 2, :c 1234, :d 4} ; maintains sort when additional kvs are assoc'd
(into [] *1)
=> [[:b 2] [:c 1234] [:d 4]]
Even if the ordering is not simple, you can write a custom comparator. This is rife with pitfalls, but there is a guide that is very good. It's not what you were originally after, but it's relevant.
I want to return all the keywords appeared in map. For instance:
{:a 1 :d 4 :e 4}
I want to get (:a :d :e). my code is
(get {:a 1 :d 4 :e 4} :keywords)
It returns nil. So how to fix it?
I guess you want to get all the keys from your map. You can do that using:
(keys {:a 1, :d 4, :e 4}
;; => (:a :d :e)
If you would like to get all the keywords when they appear as keys in a map you need to filter only those matching keyword? predicate:
(filter keyword? (keys {:a 1, 'd 4, :e 4, "f" 5}))
;; => (:a :e)
Similarly for keywords from map values:
(filter keyword? (vals {:a :b, "c" :d, 4 "e", 5 'f}))
;; => (:b :d)
I'm trying to find matching key and value pairs from a map. I'm using the following code:
(defn matches? [m k v]
(let [val (k m)]
(= val v)))
my-demo.core=> (matches? {:a 1 :b 2} :b 2)
true
my-demo.core=> (matches? {:a 1 :b 2} :b 3)
false
Another approach using superset?:
my-demo.core=> (superset? #{:a 1 :b 3} #{:a 1})
true
my-demo.core=> (superset? #{:a 1 :b 3} #{:a 2})
false
I have a feeling there is a better way to do this.
My question is: Is there an idiomatic way to find matching key and value in map in Clojure?
This is probably a small enough problem that you could just use this instead of defining a function:
(= ({:a 1 :b 2} :a)
1)
=> true
I would say this is an idiomatic way, which will work fine for most use cases.
However, it depends on the behaviour you require when testing for a nil value. because the above method would return true for :c nil:
(= ({:a 1 :b 2} :c)
nil)
=> true
And your function behaves the same way:
(matches? {:a 1 :b 2} :c nil)
=> true
To get around this you could use get with a "not found" value:
(= (get {:a 1 :b 2} :c ::not-found)
nil)
=> false
This works fine but it's perhaps not as neat. You'd just have to make sure that your "not found" value was never the same as your test value.
If you wanted to really know that a map contains a key with a possibly nil value you would instead have to check both things. Here's a function that would do this while only doing the hash-map lookup once. It uses (find map key) which returns the map entry (the key-value pair) for key, or nil if the key is not present.
(defn contains-kv? [m k v]
(if-let [kv (find m k)]
(= (val kv) v)
false))
(contains-kv? {:a 1 :b nil} :a 1)
=> true
(contains-kv? {:a 1 :b nil} :b nil)
=> true
(contains-kv? {:a 1 :b nil} :c nil)
=> false
Note: I don't think superset? is doing what you think it does. In that example you're using sets, not hash maps, which are completely different:
(clojure.set/superset? #{:a 1 :b 2} #{:a :b})
=> true
Your matches? function looks good to me, though I'd probably remove the let in this case, as it removes a bit of clutter. I'd also rename it to something more precise, though this is the best I can come up with just now:
(defn contains-kv?
"Returns true if the key k is present in the given map m and it's value matches v."
[m k v]
(= (m k) v))
So I've got the following attempt to map over a list of maps and I'm trying to get the sequence of keys that the 'keys' function returns just fine whenever I pass it a single map.
(map #(keys %) ({:a-id 1 :b 3 :c 2} {:d-id 3 :e 9 :c 1} {:a-id 3 :d-id 5 :c 2}))
which returns me a
java.lang.ClassCastException: null
I'm supposing this has something to do with the return type on keys being a sequence and by mapping over I'm guessing it's expecting a map return value??? I'm really not sure exactly why it's doing this, all I know is that it'd be dern convenient if I could get it to do in mapping what it's doing for me when I do a single application of
(keys {:a-id 1 :b 3 :c 2})
which is -- (:a-id :b :c)
(map keys '({:a-id 1 :b 3 :c 2} {:d-id 3 :e 9 :c 1} {:a-id 3 :d-id 5 :c 2}))
({:a-id 1 :b 3 :c 2} {:d-id 3 :e 9 :c 1} {:a-id 3 :d-id 5 :c 2})
Is a function call not a list. You should use list or a vector or quote the expression:
(list{:a-id 1 :b 3 :c 2} {:d-id 3 :e 9 :c 1} {:a-id 3 :d-id 5 :c 2})
Even better is to just not use lists unless you really want to create a function call. Your original code, converted to a vector of 3 maps, works great:
user=> (map #(keys %) [{:a-id 1 :b 3 :c 2} {:d-id 3 :e 9 :c 1} {:a-id 3 :d-id 5 :c 2}] )
((:a-id :c :b) (:e :c :d-id) (:a-id :c :d-id))
We leave the outer parentheses in place since (map ...) is intended to be a function call. We change the inner list to a vector, since this emphasizes that it is data (as opposed to a function call). Quoting the list also works, but is unnecessarily complex. It like saying "I am making a function call, but don't evaluate it as a function call."
I am trying to sum up values of a collection of maps by their common keys. I have this snippet:
(def data [{:a 1 :b 2 :c 3} {:a 1 :b 2 :c 3}]
(for [xs data] (map xs [:a :b]))
((1 2) (1 2))
Final result should be ==> (2 4)
Basically, I have a list of maps. Then I perform a list of comprehension to take only the keys I need.
My question now is how can I now sum up those values? I tried to use "reduce" but it works only over sequences, not over collections.
Thanks.
===EDIT====
Using the suggestion from Joost I came out with this:
(apply merge-with + (for [x data] (select-keys x [:col0 :col1 :col2]))
This iterates a collection and sums on the chosen keys. The "select-keys" part I added is needed especially to avoid to get in trouble when the maps in the collection contain literals and not only numbers.
If you really want to sum the values of the common keys you can do the whole transformation in one step:
(apply merge-with + data)
=> {:a 2, :b 4, :c 6}
To sum the sub sequences you have:
(apply map + '((1 2) (1 2)))
=> (2 4)