Is there an "assoc-if" function in the Clojure library? I.e if a value is truthy, update a map with a given key value. I've tried to find something to this effect, but came up lacking.
(defn assoc-if
[m key value]
(if value (assoc m key value) m))
If the goal is to avoid repeating m, you can use conj:
(conj m (when value [key value]))
...or Clojure 1.5's new threading macros:
(-> m
(cond-> value (assoc key value)))
If it's actually important to avoid repeating both the m and value, you'll have to write your own or reach outside clojure.core
There is no build-in assoc-if function in Clojure, but you're not the first one who needs it. Check this link with an implementation of assoc-if by ALEX MILLER:
(defn ?assoc
"Same as assoc, but skip the assoc if v is nil"
[m & kvs]
(->> kvs
(partition 2)
(filter second)
flatten
(apply assoc m)))
But, since flatten is recursive, it's best to replace it with something which is not (thanks to kotarak for the hint). Another problem of this implementation is that (apply assoc m) will fail on empty list. So, it's best to replace it to:
(defn ?assoc
"Same as assoc, but skip the assoc if v is nil"
[m & kvs]
(->> kvs
(partition 2)
(filter second)
(map vec)
(into m)))
Just use assoc-some from the medley library. Battle-tested and widely used.
Related
Is there a map-indexed alternative for clojure.core.reducers? I would like something that would work lazily like r/map (without constructing new sequence).
I suspect that what you really want to use is a transducer, since map-indexed has a 1-arity version (as does map, filter, and many other core functions) that returns a transducer. Transducers are composable, and do not create an intermediate sequence. Here is a short example:
(def xf (comp
(map-indexed (fn [i value] [i value]))
(filter (fn [[i value]] (odd? i)))
(map second)))
This says: generate an indexed vector using map-indexed, filter out only the vectors whose index is odd, and get the second element. It's a long-winded way of saying (filter odd? collection) but it's only for example purposes.
You can use this with into:
(into [] xf "ThisIsATest")
=> [\h \s \s \T \s]
or you can use the transduce function and apply str to the result:
(transduce xf str "ThisIsATest")
=> "hssTs"
I have a vector of maps like this one
(def map1
[{:name "name1"
:field "xxx"}
{:name "name2"
:requires {"element1" 1}}
{:name "name3"
:consumes {"element2" 1 "element3" 4}}])
I'm trying to define a functions that takes in a map like {"element1" 1 "element3" 6} (ie: with n fields, or {}) and fiters the maps in map1, returning only the ones that either have no requires and consumes, or have a lower number associated to them than the one associated with that key in the provided map (if the provided map doesn't have any key like that, it's not returned)
but I'm failing to grasp how to approach the maps recursive loop and filtering
(defn getV [node nodes]
(defn filterType [type nodes]
(filter (fn [x] (if (contains? x type)
false ; filter for key values here
true)) nodes))
(filterType :requires (filterType :consumes nodes)))
There's two ways to look at problems like this: from the outside in or from the inside out. Naming things carefully can really help when working with nested structures. For example, calling a vector of maps map1 may be adding to the confusion.
Starting from the outside, you need a predicate function for filtering the list. This function will take a map as a parameter and will be used by a filter function.
(defn comparisons [m]
...)
(filter comparisons map1)
I'm not sure I understand the comparisons precisely, but there seems to be at least two flavors. The first is looking for maps that do not have :requires or :consumes keys.
(defn no-requires-or-consumes [m]
...)
(defn all-keys-higher-than-values [m]
...)
(defn comparisons [m]
(some #(% m) [no-requires-or-consumes all-keys-higher-than-values]))
Then it's a matter of defining the individual comparison functions
(defn no-requires-or-consumes [m]
(and (not (:requires m)) (not (:consumes m))))
The second is more complicated. It operates on one or two inner maps but the behaviour is the same in both cases so the real implementation can be pushed down another level.
(defn all-keys-higher-than-values [m]
(every? keys-higher-than-values [(:requires m) (:consumes m)]))
The crux of the comparison is looking at the number in the key part of the map vs the value. Pushing the details down a level gives:
(defn keys-higher-than-values [m]
(every? #(>= (number-from-key %) (get m %)) (keys m)))
Note: I chose >= here so that the second entry in the sample data will pass.
That leaves only pulling the number of of key string. how to do that can be found at In Clojure how can I convert a String to a number?
(defn number-from-key [s]
(read-string (re-find #"\d+" s)))
Stringing all these together and running against the example data returns the first and second entries.
Putting everything together:
(defn no-requires-or-consumes [m]
(and (not (:requires m)) (not (:consumes m))))
(defn number-from-key [s]
(read-string (re-find #"\d+" s)))
(defn all-keys-higher-than-values [m]
(every? keys-higher-than-values [(:requires m) (:consumes m)]))
(defn keys-higher-than-values [m]
(every? #(>= (number-from-key %) (get m %)) (keys m)))
(defn comparisons [m]
(some #(% m) [no-requires-or-consumes all-keys-higher-than-values]))
(filter comparisons map1)
Given the following data structure, I want to ask for "services-list" (a component) and receive back "entity-list" (a style).
(def style->components {"entity-list" ["services-list" "employee-list" "clients-list"]})
My solution is not so elegant:
(defn get-style-name [comp-name]
(-> (filter (fn [map-entry]
(let [v (val map-entry)
found-comp (some #(= % comp-name) v)]
found-comp
)) style->components)
first
first))
Is there a better way? Perhaps my problem started with the way I structured the data.
you can make it shorter and more clojurish this way:
(defn get-style-name [comp-name]
(ffirst (filter (fn [[_ v]]
(some #{comp-name} v))
component->style)))
there is a function ffirst, that works exactly like (first (first %))
using a destructuring in the filter function signature, you can retrieve the value of the map entry, avoiding unneeded let
instead of this function in some: #(= % comp-name) it is quite common to use the set: #{comp-name}
then you can use some instead of filter, as it returns the first logical true value returned by function, so you can remove ffirst:
(defn get-style-name [comp-name]
(some (fn [[k v]]
(when (some #{comp-name} v) k))
component->style))
also, if you change your data structure to use set instead of vector, you can make it even shorter:
(def component->style {"entity-list" #{"services-list"
"employee-list"
"clients-list"}})
(defn get-style-name [comp-name]
(some (fn [[k v]] (when (v comp-name) k))
component->style))
Just to add another alternative, nested sequence operations usually lend themselves to replacement with for:
(defn get-style-name
[comp-name]
(first
(for [[style-name comp-names] style->components
comp-name' comp-names
:when (= comp-name comp-name')]
style-name)))
Still, I'd prefer a solution where the mapping of component name to style name is pre-computed, e.g.
(def get-style-name
(->> (for [[style-name comp-names] style->components
comp-name comp-names]
[comp-name style-name])
(into {})))
This way, you avoid traversing the style->components map on every lookup.
Is it ok to rely on
(= m (zipmap (keys m) (vals m)))
in Clojure 1.3+?
Having this behavior makes for slightly more readable code in some situations, eg
(defn replace-keys [smap m]
(zipmap (replace smap (keys m)) (vals m)))
vs.
(defn replace-keys [smap m]
(into {} (for [[k v] m] [(smap k k) v]))
Yes, lots of clojure would break if that changed.
Maps are stored as trees and both functions walk the same tree in the same order.
I can confirm (officially) that the answer to this is yes. The docstrings for keys and vals were updated in Clojure 1.6 to mention this (see http://dev.clojure.org/jira/browse/CLJ-1302).
(This is a question regarding style. I am aware this can be done with a bunch of conditionals, multimethods, etc.)
In the following function, null-vector is defined on each implementation. How can I set it once for the entire function? In general, is it possible to set a common binding to all implementations?
A closure won't work, since it null-vector needs an "argument", but I suppose I could partial it. However, that would still need computation of the size parameter. I'd like to avoid repeating code, obviously.
(defn path
"Returns a lazy sequence of vectors representing a monotonic path
walked over coll in n-dimensional space, where n is the cardinality
of coll's alphabet."
([coll]
(let [alphabet (set coll)
cardinality (count alphabet)
alpha-map (apply hash-map (interleave alphabet (range cardinality)))
null-vector (vec (repeat cardinality 0))]
(path coll null-vector alpha-map)))
([coll alpha-map]
(let [null-vector (vec (repeat (count (keys alpha-map)) 0))]
(path coll null-vector alpha-map)))
([coll origin alpha-map]
(let [null-vector (vec (repeat (count origin) 0))
unit-vector #(assoc null-vector (alpha-map %) 1)
sum-vectors #(vec (map + %1 %2))]
(reductions sum-vectors origin (map unit-vector coll)))))
I would create a "private" helper function:
(defn- null-copy-vector [coll]
(vec (repeat (count coll) 0)))
and then just call it in each branch of the function:
(defn path
"Returns a lazy sequence of vectors representing a monotonic path
walked over coll in n-dimensional space, where n is the cardinality
of coll's alphabet."
([coll]
(let [alphabet (set coll)
alpha-map (zipmap alphabet (iterate inc 0)) ;; note 1
null-vector (null-copy-vector alphabet)]
(path coll null-vector alpha-map null-vector)))
([coll alpha-map]
(let [null-vector (null-copy-vector alpha-map)] ;; note 2
(path coll null-vector alpha-map null-vector)))
([coll origin alpha-map]
(path coll origin alpha-map (null-copy-vector origin)))
([coll origin alpha-map null-vector]
(let [unit-vector #(assoc null-vector (alpha-map %) 1)
sum-vectors #(vec (map + %1 %2))]
(reductions sum-vectors origin (map unit-vector coll)))))
It may be this isn't satisfying to you because null-copy-vector isn't "inside" the overall function here, but I think this is pretty idiomatic. On a function that did not take multiple arities, I might use letfn to separate out an "internal" function but that won't work here.
Breaking things up like this also lets you a) reuse the basic building block functions elsewhere and b) lets you test in smaller chunks. You might want to skip the defn- and just use defn to make testing easier (although it is possible to test defn- with a bit more work).
I also broke out a new 4-arg form that takes the null-vector as the last arg, letting you pass it in directly if you know it so that you can avoid re-creating it from an already null vector. If you wanted to hide that 4-arg form, you could pull it into a separate defn- helper function.
Unrelated notes:
I modified your first branch to a simpler (imho) impl using zipmap and an infinite sequence.
Instead of (count (keys map)), just doing (count map) is sufficient (the count here is inside your helper function).