I have this collection
("string" {:1 a} "string" {:2 b} "string")
I want to only return elements that are maps.
As so,
({:1 a} {:2 b})
If your intention is to remove strings in the list, you use remove and sting? predicate. This is pretty straightforward.
user=> (remove string? '("string" {:1 a} "string" {:2 b} "string"))
({:1 a} {:2 b})
If your intention is to remove elements other than map, then you'd better use filter and map? predicate, as in #Reut's answer.
Using filter maybe?
(filter map? coll)
Output:
({:1 3} {:2 4})
Related
I have a data set that looks like this:
({"1880" 5} {"1951" 6} {"1952" 5} {"1976" 10} {"1902" 7} {"1919" 7} {"1949" 12} {"1814" 4} {"1930" 11})
I am trying to get the key with the highest value. So in the case above I want to get the value "1949" back. I believe my answer lies with max-key, however I don't fully understand how max-key works. For clarity as one answer was about looking at the string value:
I want the string "1949" as the result because it has the highest number associated with it of 12
Just use max-key, with a function to grab the val from each map:
(def data
[{"1880" 5} {"1951" 6} {"1952" 5} {"1976" 10} {"1902" 7} {"1919" 7} {"1949" 12} {"1814" 4} {"1930" 11}])
(apply max-key #(val (first %)) data) => {"1949" 12}
You need the first function to convert each single element map into a MapEntry. You can then use the val function to grab value out of the MapEntry:
(first {"1880" 5}) => <#clojure.lang.MapEntry ["1880" 5]>
(val (first {"1880" 5})) => <#java.lang.Long 5>
Be sure to bookmark The Clojure CheatSheet and peruse it often!
P.S. Why first works for this:
Note that you can convert a map into sequence of MapEntry's using either seq or vec:
some-map => <#clojure.lang.PersistentArrayMap {:a 1, :b 2}>
(seq some-map) => <#clojure.lang.PersistentArrayMap$Seq ([:a 1] [:b 2])>
(vec some-map) => <#clojure.lang.PersistentVector [[:a 1] [:b 2]]>
You then need the first item from this seq/vector, which is where first comes in:
(first (vec some-map)) => <#clojure.lang.MapEntry [:a 1]>
Note, however, that first implicitly calls seq on whatever you pass to it, so we can skip the conversion and let first implicitly convert the map into a seq of MapEntry's for us:
(first some-map) => <#clojure.lang.MapEntry [:a 1]>
You can sort your list of maps by the value of each map within it.
(last (sort-by (comp second first) data))
=> {"1949" 12}
But looking at the data, I'm wondering it wouldn't just be a single map rather than a sequence of maps. So I'm going to make the assumption that your data will never have duplicate keys, and then we can work with just a single map structure and it's easier:
(into {} data)
=> {"1919" 7, "1880" 5, "1814" 4, "1902" 7, "1951" 6, "1949" 12, "1976" 10, "1930" 11, "1952" 5}
Then you can get the same answer like this:
(last (sort-by second (into {} data)))
=> ["1949" 12]
You can call first with these outputs to get just the string "1949".
Here's another way to do it, sorting descending with a custom/reversed comparator:
(->> (into {} data)
(sort-by second #(compare %2 %1))
(ffirst))
=> "1949"
Since your keys aren't numbers (they are strings) you can't use max-key without casting to a number.
You could achieve your desired result with this:
(last (sort (mapcat keys ({"1889" 1} {"1990" 2}))))
Given
[["foo" "bar" 2] ["biz" "baf" 3]]
how do I get
[{:a "foo" :b "bar" :num 2} {:a "biz" :b "baf" :num 3}]?
In reality my vector has hundreds of vectors that need to have keys added and be converted to hash-maps.
What leetwinski said, or:
(def input [["foo" "bar" 2]["biz" "baf" 3]])
(mapv (fn [[a b num]]
{:a a
:b b
:num num}) input)
If you need to convert a lot of data, maybe mapv is not the best option because it will keep the whole vector in memory at once. Normal map which creates a lazy seq, or a transducer might be better in that case.
A general solution:
(defn vectors->maps
"takes a vector of vectors containing values and a vector of keys
and returns a vector of maps such that each value at index n in the value
vector is paired with each key at index n in the keys vector
ex: (vectors->maps [["foo" "bar" 2] ["biz" "baf" 3]], [:a :b :num])
=> [{:a "foo", :b "bar", :num 2} {:a "biz", :b "baf", :num 3}]"
[vectors keys]
(mapv (partial zipmap keys) vectors))
Exercise for the reader: writing a spec for this function and generating tests for it to ferret out any edge cases
I have a data structure as follows:
(def data {:node {:subnode 'a}, :node2 {:subnode2 'b, :subnode3 'c} })
I want to produce a list of the values of the top nodes (keys), i.e. the subnodes (vals), like this:
(:subnode 'a, :subnode2 'b, :subnode3 'c)
How can I do this? Pretty much everything I've tried so far produces:
({:subnode 'a} {:subnode2 'b, :subnode3 'c})
Where all the values are separated.
You can just extract values of each of the top level map and then flatten it:
(flatten (mapcat second data))
Alternatively to avoid deep fattening done by flatten (as noted by Leon Grapenthin) you can use solution provided by jmargolisvt or use concat:
(apply concat (mapcat second data))
If you apply conj to your map, you'll get them all in one map:
user=> data
{:node {:subnode a}, :node2 {:subnode2 b, :subnode3 c}}
user=> (apply conj (map val data))
{:subnode a, :subnode2 b, :subnode3 c}
There are library functions vals, to collect all the map's vals, and merge, to merge maps:
user> data
{:node {:subnode a}, :node2 {:subnode2 b, :subnode3 c}}
user> (apply merge (vals data))
{:subnode a, :subnode2 b, :subnode3 c}
Scala Seq has the zipWithIndex method:
def zipWithIndex[A1 >: A, That](implicit bf: CanBuildFrom[Seq[A], (A1, Int), That]): That
Zips this sequence with its indices.
returns: A new sequence containing pairs consisting of all elements of this sequence paired with their index. Indices start at 0.
Example: List("a", "b", "c").zipWithIndex = List(("a", 0), ("b", 1), ("c", 2))
What is the equivalent function in Clojure?
Clojure's map-indexed will give you an indexed list of elements in a collection.
user=> (map-indexed vector "foo")
([0 \f] [1 \o] [2 \o])
As #jmargolisvt answered map-indexed is a good solution.
As your example got index inverted with collection items, you can always compose with reverse:
(map-indexed (comp reverse list) ["a", "b", "c"])
Or map over two sequences:
(map list ["a", "b", "c"] (range))
Say I have a nested structure like this:
(def board [[:x :e :e]
[:o :x :e]
[:o :e :x]])
Why does this code transpose it 90%
(apply map vector board)
apply makes the code equivalent to this:
(map vector [:x :e :e] [:o :x :e] [:o :e :x])
map will then execute, in sequence:
(vector :x :o :o) ;; the first elements in the sequences
(vector :e :x :e) ;; the second elements in the sequences
(vector :e :e :x) ;; the third elements in the sequences
And collect them in a sequence to return. This has the effect of making the "columns" in your original sequence the new rows, and the "rows" in your original sequence the new columns.
Apply "(apply f x args) Applies fn f to the argument list formed by prepending intervening arguments to args"
What's happening is that vector is prepended to board, making the expression (apply map (cons vector board)), when the list (cons vector board) is spliced out into map by apply it becomes the expression given in YosemiteMark's answer.