I have the following vector, [-1 1 2 -1 3 0 -1 2 -1 4 0 3 0 0]
which represents the tree [[1 2 [3] [2 [4] 3]]]
where -1 begins a new branch and 0 ends it. How can I convert the original vector into a usable tree-like clojure structure (nested vector, nested map)? I think clojure.zip/zipper might do it but I'm not sure how to build those function args.
Zippers are a good tool for this:
(require '[clojure.zip :as zip])
(def in [-1 1 2 -1 3 0 -1 2 -1 4 0 3 0 0])
(def out [[1 2 [3] [2 [4] 3]]])
(defn deepen [steps]
(->> steps
(reduce (fn [loc step]
(case step
-1 (-> loc
(zip/append-child [])
(zip/down)
(zip/rightmost))
0 (zip/up loc)
(zip/append-child loc step)))
(zip/vector-zip []))
(zip/root)))
(assert (= (deepen in) out))
Somehow this feels like cheating:
[(read-string
(clojure.string/join " "
(replace {-1 "[" 0 "]"}
[-1 1 2 -1 3 0 -1 2 -1 4 0 3 0 0])))]
This is not too hard with some recursion:
(defn numbers->tree [xs]
(letfn [(step [xs]
(loop [ret [], remainder xs]
(if (empty? remainder)
[ret remainder]
(let [x (first remainder)]
(case x
0 [ret (next remainder)]
-1 (let [[ret' remainder'] (step (next remainder))]
(recur (conj ret ret'), remainder'))
(recur (conj ret x) (next remainder)))))))]
(first (step xs))))
The idea is to have a function (step) that finds a sub-tree, and returns that tree as well as what numbers are left to be processed. It proceeds iteratively (via loop) for most inputs, and starts a recursive instance of itself when it runs into a -1. The only tricky part is making sure to use the remainder returned from these recursive invocations, rather than proceeding on with the list you were in the middle of.
Related
i have a list like '(1 2 3 1 4 1 1 6 8 9 0 1) (not actually of numbers, just as an example)
I want to keep all "1" and the element next to the "1".
So the result i would want is (1 2 1 4 1 1 6 1).
Coming from an imperative point of view i would iterate over the list with a for loop, find the "1" at a certain index i and then also keep the element at index i+1.
What would a functional, Clojure idiomatic way of solving this problem be?
Using reduce you can move along the original list building a new list as you go. The reducing function f is passed the new list up until now and the next element from the old list. If the list up until now ends with a 1, or the next element is a 1, add the element to the new list. Otherwise keep the new list as is and move along.
user> (def xs [1 2 3 1 4 1 1 6 8 9 0 1])
#'user/xs
user> (defn f [x y] (if (or (= 1 y) (= 1 (peek x))) (conj x y) x))
#'user/f
user> (reduce f [] xs)
[1 2 1 4 1 1 6 1]
When you can't think of anything clever with sequence combinators, write the recursion by hand. It's not exactly elegant, but it's lazy:
(defn keep-pairs [pred coll]
(lazy-seq
(if (empty? coll)
[]
(let [x (first coll)
xs (next coll)]
(if (pred x)
(cons x (when xs
(let [y (first xs)]
(concat (when-not (pred y) [y])
(keep-pairs pred xs)))))
(when xs
(keep-pairs pred xs)))))))
user> (keep-pairs #{1} [1 2 3 1 4 1 1 6 8 9 0 1])
(1 2 1 4 1 1 6 1)
user> (take 10 (keep-pairs #{1} (cycle [1 2 3])))
(1 2 1 2 1 2 1 2 1 2)
I think I'd prefer reduce for something like this, but here's another 'functional' way of looking at it:
You have a sequence of values that should produce a potentially smaller sequence of values based on some predicate (i.e. filtering) and that predicate needs look-ahead/-behind behavior.
A less common use for map is mapping over multiple sequences at once e.g. (map f coll1 coll2 coll3). If you pass in an "offset" version of the same collection it can be used for the look-ahead/-behind logic.
(defn my-pairs [coll]
(mapcat
(fn [prev curr]
(when (or (= 1 prev) (= 1 curr))
[curr]))
(cons ::none coll) ;; these values are used for look-behind
coll))
This is (ab)using mapcat behavior to combine the mapping/filtering into one step, but it could also be phrased with map + filter.
here's one more solution with clojure's seq processors composition:
(defn process [pred data]
(->> data
(partition-by pred)
(partition-all 2 1)
(filter (comp pred ffirst))
(mapcat #(concat (first %) (take 1 (second %))))))
user> (process #{1} [1 2 1 1 3 4 1 5 1])
;;=> (1 2 1 1 3 1 5 1)
user> (process #{1} [0 1 2 1 1 1 3 4 1 5 1 6])
;;=> (1 2 1 1 1 3 1 5 1 6)
Another idea that does not work since it misses a last one:
(def v [1 2 3 1 4 1 1 6 8 9 0 1])
(mapcat (fn [a b] (when (= a 1) [a b])) v (rest v))
;; => (1 2 1 4 1 1 1 6 1)
So use two arity version of mapcat over the vector and the vector shifted one to the right.
You could check that last 1 explicitly and add, then you get a less elegant working version:
(concat
(mapcat (fn [a b] (when (= a 1) [a b])) v (rest v))
(when (= (peek v) 1) [1]))
;; => (1 2 1 4 1 1 1 6 1)
When you need to loop over data and retain state, I think a plain-old loop/recur is the most straightforward technique:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn keep-pairs
[data]
(loop [result []
prev nil
remaining data]
(if (empty? remaining)
result
(let [curr (first remaining)
keep-curr (or (= 1 curr)
(= 1 prev))
result-next (if keep-curr
(conj result curr)
result)
prev-next curr
remaining-next (rest remaining)]
(recur result-next prev-next remaining-next)))))
(dotest
(let [data [1 2 3 1 4 1 1 6 8 9 0 1]]
(is= [1 2 1 4 1 1 6 1]
(keep-pairs data))))
(defn windowed-pred [n pred]
(let [window (atom [])]
(fn [rf]
(fn ([] (rf))
([acc] (rf acc))
([acc v]
(let [keep? (or (pred v) (some pred #window))]
(swap! window #(vec (take-last n (conj %1 %2))) v)
(if keep?
(rf acc v)
acc)))))))
(let [c [1 2 3 1 4 1 1 6 8 9 0 1]
pred #(= % 1)]
(eduction (windowed-pred 1 pred) c))
(defn last-or-first? [obj pair] (or (= obj (last pair)) (= obj (first pair))))
; to test, whether previous element or element is object
(defn back-shift [l] (cons nil (butlast l))) ;; back-shifts a list
(defn keep-with-follower
[obj l]
(map #'last ; take only the element itself without its previous element
(filter #(last-or-first? obj %) ; is element or previous element the object?
(map #'list (back-shift l) l)))) ; group previous element and element in list
(def l '(1 2 3 1 4 1 1 6 8 9 0 1))
(keep-with-follower 1 l)
;; => (1 2 1 4 1 1 6 1)
A functional solution using only cons first last butlast list map filter = and defn and def.
I have to display the index of the odd items in a given list of numbers.
I tried getting the remainder but I have to divide the given list by [2 3 5 10] in order to know which element is odd.
(defn odd_one_out [y]
(println (map #(rem % 2) y)))
(odd_one_out [2 8 9 200 56])
I expect the output 9 or index of 9 since it is the only element which cannot be divided by 2.
The output i am getting is 0 0 1 0 0
If I understand correctly, you want to find the number which is uniquely indivisible for given divisors. You could use group-by to group the numbers by their divisibility, then find the one(s) that are indivisible by exactly one divisor.
(defn odd-one-out [nums divs]
(->> nums
(group-by #(map (fn [d] (zero? (mod % d))) divs))
(some (fn [[div-flags nums']]
(and (= 1 (count nums'))
(= 1 (count (filter true? div-flags)))
(first nums'))))))
(odd-one-out [2 8 9 200 56] [2 3 5 10]) ;; => 9
(odd-one-out [2 10 20 60 90] [2 3 5 10]) ;; => 2
If you just want to extend your current function, you could use map-indexed,which will give you this list ([0 0] [1 0] [2 1] [3 0] [4 0]), which you can then filter to keep only the vectors that have 1 in the second position. This will return the index of the odd character.
(defn odd-one-out [y]
(->> y
(map #(rem % 2))
(map-indexed vector)
(filter #(= 1 (second %)))
(map first)))
(odd-one-out [2 8 9 200 56])
(2)
Even better would be to use the function odd? from Clojure's standard library.
(->> [2 8 9 200 56]
(map odd?)
(map-indexed vector)
(filter #(second %))
(map first))
Another version using keep.
(to return the index)
(->> [2 8 9 200 56]
(map-indexed vector)
(keep #(when (odd? (second %))
(first %))))
(2)
(to return the value)
(->> [2 8 9 200 56]
(map-indexed vector)
(keep #(when (odd? (second %))
(second %))))
(9)
Say there's a list called xs. This list needs to be filtered by a predicate and a random element needs to be taken from the result:
(rand-nth (filter pred? xs))
This would return one item of the list. What should be done if, additionally the original list (minus the extracted item) needs to be retained?
Are those two steps necessary or is there a quicker way to do so?
(let [item (rand-nth (filter pred? xs))
new-xs (remove (partial = item) xs)]
...)
Your solution will fail for duplicated elements in your input xs as all of duplicates will be removed when they are randomly selected.
I would rather choose random index by myself and use it directly:
(defn remove-nth [xs n]
(when (seq xs)
(if (vector? xs)
(concat
(subvec xs 0 n)
(subvec xs (inc n) (count xs)))
(concat
(take n xs)
(drop (inc n) xs)))))
(defn remove-random [xs]
(if (seq xs)
(let [index (rand-int (count xs))
item (nth xs index)
remaining (remove-nth xs index)]
[item remaining])))
you could also do this without keeping the binding for item like this:
user> (defn split-rnd [pred coll]
(let [[l [it & r]] (split-with (complement
#{(rand-nth (filter pred coll))})
coll)]
[it (concat l r)]))
#'user/split-rnd
user> (split-rnd pos? [-1 2 -3 4 -5 6 -7])
[4 (-1 2 -3 -5 6 -7)]
user> (split-rnd pos? [-1 2 -3 4 -5 6 -7])
[6 (-1 2 -3 4 -5 -7)]
user> (split-rnd pos? [-1 2 -3 4 -5 6 -7])
[2 (-1 -3 4 -5 6 -7)]
I am trying to generate a relatively small (1296 elements) list of vectors essentially enumerating 4 base 6 digits from [0 0 0 0] to [5 5 5 5]
[0 0 0 0], [1 0 0 0] ... [5 0 0 0], [0 1 0 0] ... [5 5 5 5]
Currently what I have is:
(letfn [(next-v [v]
(let [active-index (some (fn [[i e]] (when (> 5 e) i))
(map-indexed vector v))]
(map-indexed #(cond
(> active-index %1) 0
(= active-index %1) (inc %2)
:else %2)
v)))]
(last (take 1290 (iterate next-v [0 0 0 0]))))
This works but it eventually blows the stack.
What am I doing here that causes the StackOverflowError?
How can I structure my code so that it is "safe"?
Is there a better way of doing what I am trying to do?
The way I would solve this is:
(def my-range
(for [i (range 0 6)
j (range 0 6)
x (range 0 6)
y (range 0 6)]
[i j x y]))
(nth my-range 1295) ;;=> [5 5 5 5]
Generalized:
(defn combine [coll]
(for [i (range 6)
j coll]
(conj j i)))
(combine (map list (range 6)))
(combine (combine (map list (range 6))))
(combine (combine (combine (map list (range 6)))))
(def result (nth (iterate combine (map list (range 6))) 3))
This is due to lazyiness in the iterated function body. Notice that the result returned by the first call of next-v is passed to next-v again, before being evaluated (because its a lazy seq), then next-v returns again an unevaluated lazy-seq which will again be passed to it.
When you realize the final lazy seq, to produce the first element all the chained seqs have to be realized to get through to your initial [0 0 0 0]. This will blow the stack.
Stuart Sierra wrote a nice article on this with more examples: http://stuartsierra.com/2015/04/26/clojure-donts-concat
You could simply wrap the map-indexed call in the let body in a vec.
Finding a more generic algorithm to your problem is recommended though.
I have used the following expression to retrieve the index of the smallest number in a vector. However, I would like to avoid the use of .indexOf (for efficiency reasons and maybe numeric precision, although I guess the numbers are implicitly converted to strings).
(.indexOf [1 2 3 4 0 5]
(reduce #(if (< %1 %2) %1 %2) [1 2 3 4 0 5] ))
Would it be possible to do it differently using reduce?
user=> (first (apply min-key second (map-indexed vector [1 2 4 0 5])))
3
I'd suggest using loop/recur if you want to do this efficiently, perhaps something like the following:
(defn min-index [v]
(let [length (count v)]
(loop [minimum (v 0)
min-index 0
i 1]
(if (< i length)
(let [value (v i)]
(if (< value minimum)
(recur value i (inc i))
(recur minimum min-index (inc i))))
min-index))))
The idea is to iterate across the whole vector, keeping track of the minimum and the index of the minimum value found so far at each point.
You can also use reduce:
(def v [1 2 3 4 0 5])
(second (reduce (fn [[curr-min min-idx curr-idx] val]
(if (< val curr-min)
[val curr-idx (inc curr-idx)]
[curr-min min-idx (inc curr-idx)])) [(first v) 0 0] v)) ;; => 4
The result of reduce is actually a three-element vector consisting of the minimum value, its index, and an index tracker (which is not important), respectively. And it traverses the collection once.
The initial value provided to reduce is basically the first element of the collection.
I know the question is old, but it is here for posterity's sake.
Following up on #Alex Taggart's answer, using thread-last macro:
user=> (->> [1 2 4 0 5]
(map-indexed vector) ; [[0 1] [1 2] [2 4] [3 0] [4 5]]
(apply min-key second) ; [3 0]
first)
3