Having two maps:
(def a {:a 1 :b 2 :c 3})
(def b {:b 222 :d 4})
placed into one vector:
(def l [a b])
what's the easiest way to construct a set (in terms of structure of unique keys) where the priority in case of key conflict (:b in this case) has a left-hand operand (:b 2 in this case). In other words I'd like to get a result:
{:a 1 :b 2 :c 3 :d 4}
Two solutions which came to mind mind are:
(apply merge-with (fn [left _] left) l)
(reduce conj (reverse l))
First one doesn't seem idiomatic for me, second one worries me because of eager list reversing which sounds a bit inneficient. Any other ideas?
Numerous other possibilities of which (reduce #(into %2 %1) l) (or with merge instead of into) could be considered. Your merge-with solution is absolutely fine.
How about
(apply merge (reverse l))
it's seems fine and simular to second one.
Related
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 need to translate an array map that has this structure:
{A [(A B) (A C)], C [(C D)], B [(B nil)], D [(D E) (D F)]}
Into this equivalent list:
'(A (B (nil)) (C (D (E) (F))))
I have this function that works just fine for not that deep structures:
(def to-tree (memoize (fn [start nodes]
(list* start
(if-let [connections (seq (nodes start))]
(map #(to-tree (second %) nodes) connections))))))
However, as the n of nested elements grows, it gives off stack overflow error. How can I optimize this function, or rather, is there a way of doing this using walk or any other functional approach?
The input data that you provide looks a lot like an adjacency list. One approach you could take would be to convert your data into a graph and then create trees from it.
Here is a solution using loom to work with graphs. This example only uses one function from loom (loom.graph/digraph), so you could probably build something similar if adding a dependency is not an option for you.
Let's start by creating a directed graph from your data structure.
(defn adj-list
"Converts the data structure into an adjacency list."
[ds]
(into {} (map
;; convert [:a [[:a :b] [:a :c]]] => [:a [:b :c]]
(fn [[k vs]] [k (map second vs)])
ds)))
(defn ds->digraph
"Creates a directed graph that mirrors the data structure."
[ds]
(loom.graph/digraph (adj-list ds)))
Once we have the graph built, we want to generate the trees from the root nodes of the graph. In your example, there is only one root node (A), but there is really nothing limiting it to just one.
Loom stores a list of all nodes in the graph as well as a set of all nodes with incoming edges to a given node in the graph. We can use these to find the root nodes.
(defn roots
"Finds the set of nodes that are root nodes in the graph.
Root nodes are those with no incoming edges."
[g]
(clojure.set/difference (:nodeset g)
(set (keys (:in g)))))
Given the root nodes, we now just need to create a tree for each. We can query the graph for the nodes adjacent to a given node, and then create trees for those recursively.
(defn to-tree [g n]
"Given a node in a graph, create a tree (lazily).
Assumes that n is a node in g."
(if-let [succ (get-in g [:adj n])]
(cons n (lazy-seq (map #(to-tree g %) succ)))
(list n)))
(defn to-trees
"Convert a graph into a collection of trees, one for each root node."
[g]
(map #(to-tree g %) (roots g)))
...and that's it! Taking your input, we can generate the desired output:
(def input {:a [[:a :b] [:a :c]] :c [[:c :d]] :b [[:b nil]] :d [[:d :e] [:d :f]]})
(first (to-trees (ds->digraph input))) ; => (:a (:c (:d (:e) (:f))) (:b (nil)))
Here are a couple of inputs for generating structures that are deep or have multiple root nodes.
(def input-deep (into {} (map (fn [[x y z]] [x [[x y] [x z]]]) (partition 3 2 (range 1000)))))
(def input-2-roots {:a [[:a :b] [:a :c]] :b [[:b nil]] :c [[:c :d]] :e [[:e :b] [:e :d]]})
(to-trees (ds->digraph input-2-roots)) ; => ((:e (:b (nil)) (:d)) (:a (:c (:d)) (:b (nil))))
One of the cool things about this approach is that it can work with infinitely nested data structures since generating the tree is lazy. You will get a StackOverflowException if you try to render the tree (because it also infinitely nested), but actually generating it is no problem.
The easiest way to play with this is to create a structure with a cycle, such as in the following example. (Note that the :c node is necessary. If only :a and :b are in the graph, there are no root nodes!)
(def input-cycle {:a [[:a :b]] :b [[:b :a]] :c [[:c :a]]})
(def ts (to-trees (ds->digraph input-cycle)))
(-> ts first second first) ;; :a
(-> ts first second second first) ;; :b
You can test for this condition using loom.alg/dag?.
I've read this kind of thing a couple of times since I've started Clojure.
For instance, here: How to convert map to a sequence?
And in some tweet I don't remember exactly that was more or less saying "if you're using flatten you're probably doing it wrong".
I would like to know, what is wrong with flatten?
I think this is what they were talking about in the answer you linked:
so> ((comp flatten seq) {:a [1 2] :b [3 4]})
(:b 3 4 :a 1 2)
so> (apply concat {:a [1 2] :b [3 4]})
(:b [3 4] :a [1 2])
Flatten will remove the structure from the keys and values, which is probably not what you want. There are use cases where you do want to remove the structure of nested sequences, and flatten was written for such cases. But for destructuring a map, you usually do want to keep the internal sequences as is.
Anything flatten can't flatten, it ought to return intact. At the top level, it doesn't.
(flatten 8)
()
(flatten {1 2, 3 4})
()
If you think you've supplied a sequence, but you haven't, you'll get the effect of supplying an empty sequence. This is the sort of leg-breaker that most core functions take care to preclude. For example, (str nil) => "".
flatten ought to work like this:
(defn flatten [x]
(if (sequential? x)
((fn flat [y] (if (sequential? y) (mapcat flat y) [y])) x)
x))
(flatten 8)
;8
(flatten [{1 2, 3 4}])
;({1 2, 3 4})
(flatten [1 [2 [[3]] 4]])
;(1 2 3 4)
You can find Steve Miner's faster lazy version of this here.
Probability of "probably"
Listen to people who say "you're probably doing it wrong", but also do not forget they say "probably", because it all depends on the problem.
For example if your task is to flatten the map where you could care less what was the key what was the value, you just need an unstructured sequence of all, then by all means, use flatten (or apply concat).
The reason it causes a "suspicion" is the fact that you had / were given a map to begin with, hence whoever gave it to you meant a "key value" paired structure, and if you flatten it, you lose that intention, as well as flexibility and clarity.
Keep in mind
In case you are still not sure what to do with a map for you particular problem, have a for comprehension in mind, since you would have a full control on what to do with the map as you iterate of it:
create a vector?
;; can also be (apply vector {:a 34 :b 42}), but just to use "for" for all consistently
user=> (into [] (for [[k v] {:a 34 :b 42}] [k v]))
[[:a 34] [:b 42]]
create another map?
user=> (into {} (for [[k v] {:a 34 :b 42}] [k (inc v)]))
{:a 35, :b 43}
create a set?
user=> (into #{} (for [[k v] {:a 34 :b 42}] [k v]))
#{[:a 34] [:b 42]}
reverse keys and values?
user=> (into {} (for [[k v] {:a 34 :b 42}] [v k]))
{34 :a, 42 :b}
I have an atom that has two parts to it.
(def thing (atom {:queue '() :map {}}))
I want to update both :queue and :map in one atomic stroke, to prevent them from getting off-sync.
Queue individually:
(swap! thing update-in [:queue] (list 1))
(From this question: How to append to a nested list in a Clojure atom?)
Map individually:
(swap! thing assoc-in [:map 1] (:key :value))
(From this question: Using swap to MERGE (append to) a nested map in a Clojure atom?)
How can I do these both within a single swap statement? (assuming that would prevent them from getting off-sync?)
You have one change you want to make, right? And you could write that change as a pure function? All you need to do is write that function, and pass it as the argument to swap!.
(defn take-from-queue [{q :queue, m :map}]
{:queue (rest q), :map (assoc m :new-task (first q))})
(swap! thing take-from-queue)
Where of course I have no idea what you actually want the body of your function to do, so I've made up something that doesn't throw an exception.
Say you have a hash-map atom:
(def m1 (atom {:a "A" :b "B"}))
To change :a and :b at the same time, changing their values to values that are different, say the numbers 1 and 2, use this function:
(defn my-swap! [params]
(swap! m1 (fn [old new] new) params))
, like so:
(my-swap! {:a 1 :b 2}) ;=> {:a 1, :b 2}
And the same effect could be achieved with the following function and execution:
(defn my-multi-swap! [params1 params2]
(swap! m1 (fn [old new1 new2] new2) params1 params2))
(my-multi-swap! {} {:a 1 :b 2}) ;=> {:a 1, :b 2}
Normally reset! is used if you want to ignore the old value. Here we use it:
(defn my-merge-swap! [params]
(swap! m1 (fn [old new] (merge old new)) params))
(my-merge-swap! {:b 3}) ;=> {:a "A", :b 3}
The first parameter to the swap! function is the existing value of the atom, and you must pass in one or more extra parameters, which you can use to give the atom its new value.
I would like to create a lazy-seq containing another lazy-seq using clojure.
The data structure that I aready have is a lazy-seq of map and it looks like this:
({:a 1 :b 1})
Now I would like to put that lazy-seq into another one so that the result would be a lazy-seq of a lazy-seq of map:
(({:a 1 :b 1}))
Does anyone know how to do this? Any help would be appreciated
Regards,
Here is an example of creating a list containing a list of maps:
=> (list (list {:a 1 :b 1}))
(({:a 1, :b 1}))
It's not lazy, but you can make both lists lazy with lazy-seq macro:
=> (lazy-seq (list (lazy-seq (list {:a 1 :b 1}))))
or the same code with -> macro:
=> (-> {:a 1 :b 1} list lazy-seq list lazy-seq)
Actually, if you'll replace lists here with vectors you'll get the same result:
=> (lazy-seq [(lazy-seq [{:a 1 :b 1}])])
(({:a 1, :b 1}))
I'm not sure what you're trying to do and why do you want both lists to be lazy. So, provide better explanation if you want further help.
generally, there's nothing special about having a lazy-seq containing many lazy-seq's, so i dont understand exactly what it is you are really after.
you could always do
(map list '({:a 1 :b 1})) ;; gives (({:a 1, :b 1}))
we can even verify that it maintains laziness:
(def a
(concat
(take 5 (repeat {:a 1 :b 2}))
(lazy-seq
(throw (Exception. "too eager")))))
(println (take 5 (map list a))) ;; works fine
(println (take 6 (map list a))) ;; throws an exception