Grouping elements using a key from a map in clojure - clojure

I have a map of the form
{[3.0 4.0][2.0 7.0][7.0 3.0][4.0 6.0][1.0 4.0][5.0 6.0][4.0 9.0][5.0 11.0][4.0 16.0]}
I want to group the second key in specific ranges like
((1-5)(6-10)(11-15)..)
The result should be
{{[3.0 4.0][7.0 3.0][1.0 4.0]}
{[2.0 7.0][4.0 6.0][5.0 6.0][4.0 9.0]}
{[5.0 11.0][4.0 16.0]}}
I have implemented using peek but have failed. How can I achieve this result?

You are confusing the result of your previous question. The output of that question (and input to this one) is a set like #{...}, not a map like {...}. Each element of the set is a length-2 vector like [3 4].
The most straightforward solution is to filter each search range like so:
(ns clj.core
(:require [tupelo.core :as t]
[datascript.core :as d]
[clojure.set :as set] ))
(t/refer-tupelo)
(def data
#{ [3.0 4.0] [2.0 7.0] [7.0 3.0] [4.0 6.0] [1.0 4.0] [5.0 6.0] [4.0 9.0] [5.0 11.0] [4.0 16.0] } )
(println "1-5:" (filter #(<= 1 (second %) 5) data))
;=> 1-5: ([3.0 4.0] [1.0 4.0] [7.0 3.0])
or we could write a loop:
(newline)
(doseq [idx (range 5)]
(let [upper (* (inc idx) 5)
lower (- upper 4) ]
(print (format "[%d..%d] => " lower upper))
(println (filter #(<= 1 (second %) 5) data))))
[1..5] => ([3.0 4.0] [1.0 4.0] [7.0 3.0])
[6..10] => ([4.0 9.0] [2.0 7.0] [4.0 6.0] [5.0 6.0])
[11..15] => ([5.0 11.0])
[16..20] => ([4.0 16.0])
[21..25] => ()
Note that I fixed the data so it is a set, not a map.
You could also use group-by:
(def result4 (into (sorted-map)
(group-by #(-> % second dec (quot 5)) data)))
(newline)
(pretty result4)
{0.0 [[3.0 4.0] [1.0 4.0] [7.0 3.0]],
1.0 [[4.0 9.0] [2.0 7.0] [4.0 6.0] [5.0 6.0]],
2.0 [[5.0 11.0]],
3.0 [[4.0 16.0]]}
and you can pull out the values like
(newline)
(pp/pprint (vals result4))
([[3.0 4.0] [1.0 4.0] [7.0 3.0]]
[[4.0 9.0] [2.0 7.0] [4.0 6.0] [5.0 6.0]]
[[5.0 11.0]]
[[4.0 16.0]])

Related

Why doesn't map convey dynamic bindings? [duplicate]

From what I understand, setting a new binding on a dynamic var affects all functions called within that binding, and all functions called from those functions.
Why does the binding appear to be lost in the first example below?
(def ^:dynamic *out-dir* "/home/user")
(binding [*out-dir* "/home/dave"] (map #(str *out-dir* %) [1 2 3]))
; gives: ("/home/user1" "/home/user2" "/home/user3")
; expected: ("/home/dave1" "/home/dave2" "/home/dave3")
(binding [*out-dir* "/home/dave"] (conj (map #(str *out-dir* %) [1 2 3]) *out-dir*))
; gives: ("/home/dave" "/home/dave1" "/home/dave2" "/home/dave3")
This is caused by lazyness - map returns a lazy sequence which is defined inside the binding but is evaluated outside. You need to force the evaluation from inside:
(binding [*out-dir* "/home/dave"]
(doall (map #(str *out-dir* %) [1 2 3])))
It's true that laziness and dynamic bindings can cause problems; however, abandoning laziness is not the only solution. If you wish to preserve laziness (or to use dynamic bindings with pmap), use bound-fn or bound-fn*.
(def ^:dynamic x 0)
=> (binding [x 3] (map #(+ x %) (range 10)))
;; (0 1 2 3 4 5 6 7 8 9)
=> (binding [x 3] (map (bound-fn [y] (+ x y)) (range 10)))
;; (3 4 5 6 7 8 9 10 11 12)
=> (binding [x 3] (map (bound-fn* #(+ % x)) (range 10)))
;; (3 4 5 6 7 8 9 10 11 12)
Another solution is to use Python-style generator functions available via lazy-gen and yield from the Tupelo library:
(ns tst.demo.core
(:use demo.core tupelo.test)
(:require
[tupelo.core :as t] ))
(t/refer-tupelo)
(def ^:dynamic foo 1)
(dotest
(let [result (binding [foo 3]
(lazy-gen
(doseq [x (range 3)]
(yield {:foo foo :x x})))) ]
(println result)))
result => ({:foo 3, :x 0}
{:foo 3, :x 1}
{:foo 3, :x 2})

Clojure - Function that returns all the indices of a vector of vectors

If I have a vector [[[1 2 3] [4 5 6] [7 8 9]] [[10 11] [12 13]] [[14] [15]]]
How can I return the positions of each element in the vector?
For example 1 has index [0 0 0], 2 has index [0 0 1], etc
I want something like
(some-fn [[[1 2 3] [4 5 6] [7 8 9]] [[10 11] [12 13]] [[14] [15]]] 1)
=> [0 0 0]
I know that if I have a vector [1 2 3 4], I can do (.indexOf [1 2 3 4] 1) => 0 but how can I extend this to vectors within vectors.
Thanks
and one more solution with zippers:
(require '[clojure.zip :as z])
(defn find-in-vec [x data]
(loop [curr (z/vector-zip data)]
(cond (z/end? curr) nil
(= x (z/node curr)) (let [path (rseq (conj (z/path curr) x))]
(reverse (map #(.indexOf %2 %1) path (rest path))))
:else (recur (z/next curr)))))
user> (find-in-vec 11 data)
(1 0 1)
user> (find-in-vec 12 data)
(1 1 0)
user> (find-in-vec 18 data)
nil
user> (find-in-vec 8 data)
(0 2 1)
the idea is to make a depth-first search for an item, and then reconstruct a path to it, indexing it.
Maybe something like this.
Unlike Asthor's answer it works for any nesting depth (until it runs out of stack). Their answer will give the indices of all items that match, while mine will return the first one. Which one you want depends on the specific use-case.
(defn indexed [coll]
(map-indexed vector coll))
(defn nested-index-of [coll target]
(letfn [(step [indices coll]
(reduce (fn [_ [i x]]
(if (sequential? x)
(when-let [result (step (conj indices i) x)]
(reduced result))
(when (= x target)
(reduced (conj indices i)))))
nil, (indexed coll)))]
(step [] coll)))
(def x [[[1 2 3] [4 5 6] [7 8 9]] [[10 11] [12 13]] [[14] [15]]])
(nested-index-of x 2) ;=> [0 0 1]
(nested-index-of x 15) ;=> [2 1 0]
Edit: Target never changes, so the inner step fn doesn't need it as an argument.
Edit 2: Cause I'm procrastinating here, and recursion is a nice puzzle, maybe you wanted the indices of all matches.
You can tweak my first function slightly to carry around an accumulator.
(defn nested-indices-of [coll target]
(letfn [(step [indices acc coll]
(reduce (fn [acc [i x]]
(if (sequential? x)
(step (conj indices i) acc x)
(if (= x target)
(conj acc (conj indices i))
acc)))
acc, (indexed coll)))]
(step [] [] coll)))
(def y [[[1 2 3] [4 5 6] [7 8 9]] [[10 11] [12 13]] [[14] [15 [16 17 4]]]])
(nested-indices-of y 4) ;=> [[0 1 0] [2 1 1 2]]
Vectors within vectors are no different to ints within vectors:
(.indexOf [[[1 2 3] [4 5 6] [7 8 9]] [[10 11] [12 13]] [[14] [15]]] [[14] [15]])
;;=> 2
The above might be a bit difficult to read, but [[14] [15]] is the third element.
Something like
(defn indexer [vec number]
(for [[x set1] (map-indexed vector vec)
[y set2] (map-indexed vector set1)
[z val] (map-indexed vector set2)
:when (= number val)]
[x y z]))
Written directly into here so not tested. Giving more context on what this would be used for might make it easier to give a good answer as this feels like something you shouldn't end up doing in Clojure.
You can also try and flatten the vectors in some way
An other solution to find the path of every occurrences of a given number.
Usually with functional programming you can go for broader, general, elegant, bite size solution. You will always be able to optimize using language constructs or techniques as you need (tail recursion, use of accumulator, use of lazy-seq, etc)
(defn indexes-of-value [v coll]
(into []
(comp (map-indexed #(if (== v %2) %1))
(remove nil?))
coll))
(defn coord' [v path coll]
(cond
;; node is a leaf: empty or coll of numbers
(or (empty? coll)
(number? (first coll)))
(when-let [indexes (seq (indexes-of-value v coll))]
(map #(conj path %) indexes))
;; node is branch: a coll of colls
(coll? (first coll))
(seq (sequence (comp (map-indexed vector)
(mapcat #(coord' v (conj path (first %)) (second %))))
coll))))
(defn coords [v coll] (coord' v [] coll))
Execution examples:
(def coll [[2 1] [] [7 8 9] [[] [1 2 2 3 2]]])
(coords 2 coll)
=> ([0 0] [3 1 1] [3 1 2] [3 1 4])
As a bonus you can write a function to test if paths are all valid:
(defn valid-coords? [v coll coords]
(->> coords
(map #(get-in coll %))
(remove #(== v %))
empty?))
and try the solution with input generated with clojure.spec:
(s/def ::leaf-vec (s/coll-of nat-int? :kind vector?))
(s/def ::branch-vec (s/or :branch (s/coll-of ::branch-vec :kind vector?
:min-count 1)
:leaf ::leaf-vec))
(let [v 1
coll (first (gen/sample (s/gen ::branch-vec) 1))
res (coords v coll)]
(println "generated coll: " coll)
(if-not (valid-coords? v coll res)
(println "Error:" res)
:ok))
Here is a function that can recursively search for a target value, keeping track of the indexes as it goes:
(ns tst.clj.core
(:use clj.core tupelo.test)
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(defn index-impl
[idxs data tgt]
(apply glue
(for [[idx val] (zip (range (count data)) data)]
(let [idxs-curr (append idxs idx)]
(if (sequential? val)
(index-impl idxs-curr val tgt)
(if (= val tgt)
[{:idxs idxs-curr :val val}]
[nil]))))))
(defn index [data tgt]
(keep-if not-nil? (index-impl [] data tgt)))
(dotest
(let [data-1 [1 2 3]
data-2 [[1 2 3]
[10 11]
[]]
data-3 [[[1 2 3]
[4 5 6]
[7 8 9]]
[[10 11]
[12 13]]
[[20]
[21]]
[[30]]
[[]]]
]
(spyx (index data-1 2))
(spyx (index data-2 10))
(spyx (index data-3 13))
(spyx (index data-3 21))
(spyx (index data-3 99))
))
with results:
(index data-1 2) => [{:idxs [1], :val 2}]
(index data-2 10) => [{:idxs [1 0], :val 10}]
(index data-3 13) => [{:idxs [1 1 1], :val 13}]
(index data-3 21) => [{:idxs [2 1 0], :val 21}]
(index data-3 99) => []
If we add repeated values we get the following:
data-4 [[[1 2 3]
[4 5 6]
[7 8 9]]
[[10 11]
[12 2]]
[[20]
[21]]
[[30]]
[[2]]]
(index data-4 2) => [{:idxs [0 0 1], :val 2}
{:idxs [1 1 1], :val 2}
{:idxs [4 0 0], :val 2}]

Finding the smallest difference between a sorted-set of floats

If I've got a sorted-set of floats, how can I find the smallest difference between any 2 values in that sorted set?
For example, if the sorted set contains
#{1.0 1.1 1.3 1.45 1.7 1.71}
then the result I'm after would be 0.01, as the difference between 1.71 and 1.7 is the smallest difference between any 2 values in that sorted set.
EDIT
As Alan pointed out to me, the problem stated this was a sorted set, so we could do this much simpler:
(def s (sorted-set 1.0 1.1 1.3 1.45 1.7 1.71))
(reduce min (map - (rest s) s)))
=> 0.01
Original Answer
Assuming the set is unordered, although ordering it might be better.
Given
(def s #{1.0 1.1 1.3 1.45 1.7 1.71})
We could get relevant pairs, as in, for every number in the list, pair it with all the numbers to the right of it:
(def pairs
(loop [r [] s (into [] s)]
(if-let [[f & v] s]
(recur (concat r (for [i v] [f i]))
v)
r)))
=> ([1.0 1.45] [1.0 1.7] [1.0 1.3] [1.0 1.1] [1.0 1.71] [1.45 1.7] [1.45 1.3]
[1.45 1.1] [1.45 1.71] [1.7 1.3] [1.7 1.1] [1.7 1.71] [1.3 1.1] [1.3 1.71]
[1.1 1.71])
Now, we will want to look at the absolute values of the differences between every pair:
(defn abs [x] (Math/abs x))
Put it all together, and get the minimum value:
(reduce min (map (comp abs (partial apply -)) pairs))
Which will give us the desired output, 0.01
That last line could be more explicitly written as
(reduce min
(map (fn[[a b]]
(abs (- a b)))
pairs))
I think using the Clojure built-in function partition is the simplest way:
(ns clj.core
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(def vals [1.0 1.1 1.3 1.45 1.7 1.71])
(spyx vals)
(def pairs (partition 2 1 vals))
(spyx pairs)
(def deltas (mapv #(apply - (reverse %)) pairs))
(spyx deltas)
(println "result=" (apply
vals => [1.0 1.1 1.3 1.45 1.7 1.71]
pairs => ((1.0 1.1) (1.1 1.3) (1.3 1.45) (1.45 1.7) (1.7 1.71))
deltas => [0.10000000000000009 0.19999999999999996 0.1499999999999999 0.25 0.010000000000000009]
result= 0.010000000000000009

How to combine elements from two lists

I want to combine elements from two lists, my program looks like this
(ns datamodel
(:use
[net.cgrand.enlive-html :as en-html ])
(:require
[clojure.zip :as z]
[clojure.data.zip.xml :only (attr text xml->) :as xz]
[clojure.xml :as xml ]
[clojure.data.zip.xml :as zf]
[clojure.java.io :as io]
))
(def data-url "http://api.eventful.com/rest/events/search?app_key=4H4Vff4PdrTGp3vV&keywords=music&location=Belgrade&date=Future")
(defn map-tags-contents [url & tags]
(map #(hash-map % (keyword (last tags)))
(mapcat (comp :content z/node)
(apply xz/xml->
(-> url xml/parse z/xml-zip)
(for [t tags]
(zf/tag= t)
)))))
(def titles (map-tags-contents data-url :events :event :title))
(def descriptions (map-tags-contents data-url :events :event :description))
(defn create-map [](for [el1 titles
el2 descriptions] (into {} (conj el1 el2 ))))
But when I call create-map resulting maps in list are duplicated. I see that I got Cartesian join, because I didn't say the way elements will be combined. And I want first element from first map and first from second map to be combined, second element from first map and second from second map, etc...
Element-wise combination
(map list [1 2 3] [:a :b :c]) ;=> ((1 :a) (2 :b) (3 :c))
Cartesian product
(for [x [1 2 3], y [:a :b :c]] (list x y))
;=> ((1 :a) (1 :b) (1 :c) (2 :a) (2 :b) (2 :c) (3 :a) (3 :b) (3 :c))
So the fn should look like this
(defn create-map [](map conj titles descriptions ))
Thank to #A. Webb

Idiomatic way for finding if an element exists in an nested vector

I have modeled my data as embedded vectors. I need to find if an element exists within these vectors. I have the below code which does it correctly. However, I'd like suggestions on a more idiomatic way to do it.
(defn exists-in-vector?
[my-vec my-sym]
(= my-sym (first my-vec)))
(defn exists-in-vectors?
[all-vectors my-symbol]
(empty? (for [first-vector all-vectors
second-vector first-vector
third-vector second-vector
:when (exists-in-vector? third-vector my-symbol)
:while (exists-in-vector? third-vector my-symbol)]
true)))
> (exists-in-vectors? [[[[:a 20] [:b :30]] [[:c 20] [:d :30]]]
[[[:h 20] [:g :30]] [[:f 20] [:e :30]]]]
:a) => true
This is one of the few cases where 'flatten' is exactly what you want:
(def vectors [[[[:a 20] [:b :30]] [[:c 20] [:d :30]]]
[[[:h 20] [:g :30]] [[:f 20] [:e :30]]]])
(some #{:g} (flatten vectors))
;=> :g
(some #{:k} (flatten vectors))
;=> nil
By the way, the definition of flatten is interesting.
(source flatten) or http://clojuredocs.org/clojure_core/clojure.core/flatten :
(defn flatten
"Takes any nested combination of sequential things (lists, vectors,
etc.) and returns their contents as a single, flat sequence.
(flatten nil) returns nil."
{:added "1.2"
:static true}
[x]
(filter (complement sequential?)
(rest (tree-seq sequential? seq x))))
A nested vector may be thought of as a tree
(def tree [[[[:a 20] [:b :30]] [[:c 20] [:d :30]]]
[[[:h 20] [:g :30]] [[:f 20] [:e :30]]]])
(some #(= :a %) (tree-seq vector? identity tree))
;=> true
(some #(= :k %) (tree-seq vector? identity tree))
;=> nil
user=> (defn in-nested? [thing elt]
#_=> (if (vector? thing)
#_=> (boolean (some #(in-nested? % elt) thing))
#_=> (= thing elt)))
#'user/in-nested?
user=> (def data [[[[:a 20] [:b :30]] [[:c 20] [:d :30]]] [[[:h 20] [:g :30]] [[:f 20] [:e :30]]]])
#'user/data
user=> (in-nested? data :a)
true
user=> (in-nested? data :c)
true
user=> (in-nested? data :z)
false
user=> (in-nested? data 20)
true
user=> (in-nested? data 40)
false