I've currently implemented a way to sort by a deep key in a map like so:
(sort-by #(get-in % [:layer :order]) [{:layer {:order 1} {:layer {:order 2}])
I was wondering if there was a way to do this using map destructuring? Is that available for functions outside of let and parameter definition? An example of what I'm wondering is possible:
(sort-by {:layer {:order}} [{:layer {:order 1} {:layer {:order 2}])
As far as I'm aware, you can only destructure within a let binding or function binding. This is how you might do it with nested map destructuring:
(sort-by (fn [{{o :order} :layer}] o)
[{:layer {:order 2}}
{:layer {:order 1}}])
I don't think that's any clearer, though. Since keywords are functions, you could also use plain old function composition:
(sort-by (comp :order :layer)
[{:layer {:order 2}}
{:layer {:order 1}}])
I don't think so because sort-by needs a value extraction function (keyfn)
(that is unless you want to sort entries directly by themself)
user=> (doc sort-by)
-------------------------
clojure.core/sort-by
([keyfn coll] [keyfn comp coll])
Returns a sorted sequence of the items in coll, where the sort
order is determined by comparing (keyfn item). If no comparator is
supplied, uses compare. comparator must implement
java.util.Comparator. If coll is a Java array, it will be modified.
To avoid this, sort a copy of the array.
EDIT: what you can do is "simulate" get-in via compose and keyword lookups as in
(sort-by (comp :a :c) [ {:c {:a 3}} {:c {:a 2}} ])
Related
I really like using contains? because it's so terse and readable. I want to see if a set contains maps that have the same key and value pairs of an example that also had other key value pairs. I'm pretty sure contains? won't work here. Is there an alternative? Maybe I'll have to write one (I'm finally getting into the mindset!). For example, if I had
(def some-set #{{:foo "bar" :beep "boop"}{:foo "bar"} {:foo "bar" :hi "there"}})
what would be a quick way to know if it had any maps that matched {:foo "bar" :one "two"} on :foo "bar"?
Edited: Remembering that a map is a collection of key-value vectors, here is an implementation for the predicate submap?:
(defn submap?
"Returns true if subm is a submap of m, false otherwise."
[subm m]
(every? (fn [[k v]] (= (get m k ::not-found) v)) subm))
This predicate can be used to filter any collection:
(filter #(submap? {:a 1 :b 2} %) [{:a 1} {:a 1 :b 2 :c 3}])
=> ({:a 1, :b 2, :c 3})
Original answer
This solution works but is slower than my updated answer, due to the construction of (set m) for large m
(defn submap?
"Returns true if subm is a submap of m, false otherwise."
[subm m]
(let [kvs (set m)]
(every? kvs subm)))
A generic way would be to write a predicate, that checks if a map
contains another map. This can be done using select-keys to only get
a map with certain keys; using the keys from the map to compare and
then just comparing the result will give you that.
(def maps #{{:foo "bar" :beep "boop"} {:foo "bar"} {:foo "bar" :hi "there"} {:foo "baz"}})
(defn submap?
[submap m]
(= (select-keys m (keys submap)) submap))
(println
(filter (partial submap? {:foo "bar"}) maps))
; → ({:foo bar, :beep boop} {:foo bar, :hi there} {:foo bar})
Yet this is just a simple sequential search. This does not (and AFAIR
there is nothing in core to help) utilize your maps being in a set.
Also note, that the order of the result is undefined since the order of
sets is too.
You can find many predicates of this nature and related helper functions in the Tupelo library, in particular:
submap?
submatch?
wild-match?
wild-submatch?
These are especially helpful in writing unit tests. For example, you may only care about certain fields like :body when testing a webserver response, and you want to ignore other fields like the IP address or a timestamp.
The unit tests show the code in action.
In clojure, given a data structure [{:a "foo" :b "bar"} {:a "biz" :b "baz"}] how would I get [{:b "bar"}{:b "baz"}] the most succinctly?
dissoc is a function for dissociating a key from an associative structure like a map. Here's how you'd do it with one map:
(dissoc my-map :a)
If you have a sequence of maps, you can map a function over them to dissoc the key(s) from each map:
(map #(dissoc % :a) the-maps)
This phrasing passes an anonymous function to map, but depending on usage you may want to extract a named function:
(defn fix-the-map [m]
(dissoc m :a))
(map fix-the-map the-maps)
#Taylor's above answer to dissoc :a from each map is fine if you want all maps without :a.
In case if you want a list of maps with just :b key, you can do
<!-- language-all: lang-clj -->
;; Assuming my-map is the object map
;; map returns a lazy sequence
(map #(hash-map :b (:b %)) my-map)
;; or
(map #(select-keys % [:b]) mp)
What is the idiomatic way of returning the next item in collection, given a member in a collection?
For example, given (def coll [:a :b :c :d :e :f]), what should the f be to make (f coll :d) return :e?
Typically this is just not a thing one does very much in Clojure. The only possible implementation requires a linear scan of the input collection, which means that you are using the wrong data structure for this task.
Instead, we usually try to structure our data so that it is convenient for the tasks we need to perform on it. How best to do this will depend on why you want to look up "the element after foo". For example, if you are going the input one item at a time and want to know the next item as well as the current item, you could write (partition 2 1 input) to get a sequence of pairs of adjacent values.
That is, you ask for an idiomatic implementation, but there is none: the idiom is to solve the problem differently. Of course it is straightforward to write the loop yourself, if you believe you are in an exceptional case where you are using the right data structure and just need to do this weird thing once or twice.
As #amalloy said in his answer, this isn't something for which you would want to use the original data structure, because it would require a linear lookup every time. In other words, your (f coll :d) pattern wouldn't be a particularly useful thing due to its performance.
However, what you could do is define a function that, given a collection, builds a data structure that makes this sort of lookup efficient, and use that as your function. It might look something like this:
(defn after [xs]
(into {} (map vec (partition 2 1 xs))))
Examples:
(-> [:a :b :c :d :e :f] after :d)
;;=> :e
(let [xs [:a :b :c :d :e :f]
f (after xs)]
(map f xs))
;;=> (:b :c :d :e :f nil)
If we generalise the problem to finding the thing following the first thing to pass a test, we get something like
(defn following [pred coll]
(->> coll
(drop-while (complement pred))
(second)))
For example,
(following #{6} (range))
=> 7
Or, your example,
(following #{:d} coll)
=> :e
This is no more or less idiomatic than take-while or drop-while.
I have a question regarding two functions, one taking a complete map and the other specific keywords like so:
(def mapVal
{:test "n"
:anotherKey "n"})
(defn functionTest
[& {:keys [test anotherKey] :or {:test "d" :anotherKey "d"}}]
(println :test :anotherKey))
(defn mapFunc
[map]
(functionTest (get-in map [:test :anotherKey])))
The goal would be that all the keys in the parameter map will be passed correctly to the functionTest. Is there anyway this could work? I tried a few things but i just cant get all the keywords and values passed to the functionTest. What i dont want is just the values of the map, it should be passed to the other function with keyword and value.
You're pretty close. A few things should clear it up.
First, when you declare parameters with [& varname] that means varname will be a list containing all the extra parameters. So you don't need to use that '&' here to destructure the input. Instead, you just name which keys you want to have become variables.
Try this:
(defn functionTest
[{:keys [test anotherKey]}]
(println test anotherKey))
And the other problem is using get-in. With get-in you're defining a "path" through nested data structures with that vector. For example, given:
{:first {:a 1 :b 2} :second {:c 3 :d 4}}
You could use get-in to get the value at :second :c with this:
(get-in {:first {:a 1 :b 2} :second {:c 3 :d 4}} [:second :c])
In your case, you don't need to use get-in at all. You just need to pass the entire map. The destructuring you defined in functionTest will handle the rest. Here is what I did that worked:
(defn mapFunc
[map]
(functionTest map))
I would also suggest you not name the that variable 'map' since it conflicts with the map function.
get-in is for accessing nested associative data structures.
(def m {:a {:x 1}})
(get-in m [:a :x]) ;;=> 1
After you destructure a map those values are in scope and are accessed via symbols. Your example should look like this:
(def mapVal
{:test "n"
:anotherKey "n"})
(defn functionTest
[& {:keys [test anotherKey]
:or {:test "d" :anotherKey "d"}}]
(println test anotherKey))
(defn mapFunc
[m]
(apply functionTest (apply concat (select-keys m [:test :anotherKey]))))
(mapFunc mapVal) ;;=> prints: n n
You have to go through this because functionTest is accepting bare key value pairs as optional parameters (the ones to the right of the &), as in:
(functionTest :test "n"
:anotherKey "n" )
;;=> Also prints: n n
select-keys returns a map with only the specified keys:
(select-keys mapVal [:test])
;; => {:test "n"}
applying concat to a map returns a flat seq of keys and values:
(apply concat (select-keys mapVal [:test :anotherKey]))
;; => (:test "n" :anotherKey "n")
apply applies a function to a seq, as though the seq were its argument list:
(+ [1 2 3]) ;;=> Error.
(apply + [1 2 3]) ;; => 6
As a side note, conventionally in Clojure code, snake-case is preferred to camelCase for most names.
Following up from this question: Idiomatic clojure map lookup by keyword
Map access using clojure can be done in many ways.
(def m {:a 1}
(get m :a) ;; => 1
(:a m) ;; => 1
(m :a) ;; => 1
I know I use mainly the second form, and sometimes the third, rarely the first. what are the advantages (speed/composability) of using each?
get is useful when the map could be nil or not-a-map, and the key could be something non-callable (i.e. not a keyword)
(def m nil)
(def k "some-key")
(m k) => NullPointerException
(k m) => ClassCastException java.lang.String cannot be cast to clojure.lang.IFn
(get m k) => nil
(get m :foo :default) => :default
From the clojure web page we see that
Maps implement IFn, for invoke() of one argument (a key) with an
optional second argument (a default value), i.e. maps are functions of
their keys. nil keys and values are ok.
Sometimes it is rewarding to take a look under the hoods of Clojure. If you look up what invoke looks like in a map, you see this:
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L196
It apparently calls the valAt method of a map.
If you look at what the get function does when called with a map, this is a call to clojure.lang.RT.get, and this really boils down to the same call to valAt for a map (maps implement ILookUp because they are Associatives):
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L634.
The same is true for a map called with a key and a not-found-value. So, what is the advantage? Since both ways boil down to pretty much the same, performance wise I would say nothing. It's just syntactic convenience.
You can pass get to partial etc. to build up HOFs for messing with your data, though it doesn't come up often.
user=> (def data {"a" 1 :b 2})
#'user/data
user=> (map (partial get data) (keys data))
(1 2)
I use the third form a lot when the data has strings as keys
I don't think there is a speed difference, and even if that would be the case, that would be an implementation detail.
Personally I prefer the second option (:a m) because it sometimes makes code a bit easier on the eye. For example, I often have to iterate through a sequence of maps:
(def foo '({:a 1} {:a 2} {:a 3}))
If I want to filter all values of :a I can now use:
(map :a foo)
Instead of
(map #(get % :a) foo)
or
(map #(% :a) foo)
Of course this is a matter of personal taste.
To add to the list, get is also useful when using the threading macro -> and you need to access via a key that is not a keyword
(let [m {"a" :a}]
(-> m
(get "a")))
One advantage of using the keyword first approach is it is the most concise way of accessing the value with a forgiving behavior in the case the map is nil.