Clojure's maps: are keys and vals in same order? - clojure

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).

Related

clojure: filtering a vector of maps by keys existence and values

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)

Return the key, where the value is a vector, when asking for a value that might be in that vector

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.

"->>" macro and iterative function application

I'm working through a book on clojure and ran into a stumbling block with "->>". The author provides an example of a comp that converts camelCased keywords into a clojure map with a more idiomatic camel-cased approach. Here's the code using comp:
(require '[clojure.string :as str])
(def camel->keyword (comp keyword
str/join
(partial interpose \-)
(partial map str/lower-case)
#(str/split % #"(?<=[a-z])(?=[A-Z])")))
This makes a lot of sense, but I don't really like using partial all over the place to handle a variable number of arguments. Instead, an alternative is provided here:
(defn camel->keyword
[s]
(->> (str/split s #"(?<=[a-z])(?=[A-Z])")
(map str/lower-case)
(interpose \-)
str/join
keyword))
This syntax is much more readable, and mimics the way I would think about solving a problem (front to back, instead of back to front). Extending the comp to complete the aforementioned goal...
(def camel-pairs->map (comp (partial apply hash-map)
(partial map-indexed (fn [i x]
(if (odd? i)
x
(camel->keyword x))))))
What would be the equivalent using ->>? I'm not exactly sure how to thread map-indexed (or any iterative function) using ->>. This is wrong:
(defn camel-pairs->map
[s]
(->> (map-indexed (fn [i x]
(if (odd? i)
x
(camel-keyword x)))
(apply hash-map)))
Three problems: missing a parenthesis, missing the > in the name of camel->keyword, and not "seeding" your ->> macro with the initial expression s.
(defn camel-pairs->map [s]
(->> s
(map-indexed
(fn [i x]
(if (odd? i)
x
(camel->keyword x))))
(apply hash-map)))
Is this really more clear than say?
(defn camel-pairs->map [s]
(into {}
(for [[k v] (partition 2 s)]
[(camel->keyword k) v])))

Assoc-if in Clojure

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.

How do I write a predicate that checks if a value exists in an infinite seq?

I had an idea for a higher-order function today that I'm not sure how to write. I have several sparse, lazy infinite sequences, and I want to create an abstraction that lets me check to see if a given number is in any of these lazy sequences. To improve performance, I wanted to push the values of the sparse sequence into a hashmap (or set), dynamically increasing the number of values in the hashmap whenever it is necessary. Automatic memoization is not the answer here due to sparsity of the lazy seqs.
Probably code is easiest to understand, so here's what I have so far. How do I change the following code so that the predicate uses a closed-over hashmap, but if needed increases the size of the hashmap and redefines itself to use the new hashmap?
(defn make-lazy-predicate [coll]
"Returns a predicate that returns true or false if a number is in
coll. Coll must be an ordered, increasing lazy seq of numbers."
(let [in-lazy-list? (fn [n coll top cache]
(if (> top n)
(not (nil? (cache n)))
(recur n (next coll) (first coll)
(conj cache (first coll)))]
(fn [n] (in-lazy-list? n coll (first coll) (sorted-set)))))
(def my-lazy-list (iterate #(+ % 100) 1))
(let [in-my-list? (make-lazy-predicate my-lazy-list)]
(doall (filter in-my-list? (range 10000))))
How do I solve this problem without reverting to an imperative style?
This is a thread-safe variant of Adam's solution.
(defn make-lazy-predicate
[coll]
(let [state (atom {:mem #{} :unknown coll})
update-state (fn [{:keys [mem unknown] :as state} item]
(let [[just-checked remainder]
(split-with #(<= % item) unknown)]
(if (seq just-checked)
(-> state
(assoc :mem (apply conj mem just-checked))
(assoc :unknown remainder))
state)))]
(fn [item]
(get-in (if (< item (first (:unknown #state)))
#state
(swap! state update-state item))
[:mem item]))))
One could also consider using refs, but than your predicate search might get rolled back by an enclosing transaction. This might or might not be what you want.
This function is based on the idea how the core memoize function works. Only numbers already consumed from the lazy list are cached in a set. It uses the built-in take-while instead of doing the search manually.
(defn make-lazy-predicate [coll]
(let [mem (atom #{})
unknown (atom coll)]
(fn [item]
(if (< item (first #unknown))
(#mem item)
(let [just-checked (take-while #(>= item %) #unknown)]
(swap! mem #(apply conj % just-checked))
(swap! unknown #(drop (count just-checked) %))
(= item (last just-checked)))))))