reduce a nested vector to another one in Clojure - algorithm

What is an idiomatic way of handling such stuff in Clojure?
I have:
(def data1
[1 [2 3]])
(def data2
[1 [[2 [3 [4]]]
[22 33]]])
I want to get:
[1 2 3]
and
[[1 2 3 4]
[1 22 33]]
respectively. The nested levels of inner vectors may be of different lengths.
I cannot wrap my head around the nature of such inputs and looking for help. Basically a function should map an input (which is a vector) to an output (vector, also) which, in essence, is a vector of all the "routes" from its head to the innermost elements. This is a vague explanation, will be grateful for a better one.

(defn transform [[f & r]]
(let [rr (apply concat r)]
(if (= (flatten rr) rr)
(vec (cons f rr))
(mapv #(if (vector? %)
(vec (cons f (flatten %)))
[f %])
rr))))
; Test Cases
(transform [1 [2 3]]) => [1 2 3]
(transform [1 [[2 [3 [4]]] [22 33]]]) => [[1 2 3 4] [1 22 33]]
(transform [1 [[2 [3 [4]]] [22 33] 44]]) => [[1 2 3 4] [1 22 33] [1 44]
(transform [1]) => [1]
(transform [1 [2]]) => [1 2]

(defn transform [v]
(let [[x & [xs]] v]
(loop [r xs
res []]
(cond
(empty? r) res
(vector? (first r)) (recur (rest r)
(conj res
(into
(conj [] x)
(flatten (first r)))))
:else (into (conj res x) r)))))
(def data1
[1 [2 3]])
(def data2
[1 [[2 [3 [4]]]
[22 33]]])
(def data3
[1 [[20 25 [30 [40 [50]]]]
[2 3 [4 5 [6 7 [8 9]]]]
[[60] 70 [80 [90 100 [110 120 130 [140 150]]]]]]])
; user=> (transform data1)
; [1 2 3]
; user=> (transform data2)
; [[1 2 3 4] [1 22 33]]
; user=> (transform data3)
; [[1 20 25 30 40 50] [1 2 3 4 5 6 7 8 9] [1 60 70 80 90 100 110 120 130 140 150]]

Related

LeetCode 1: How to translate the question two sum from ReasonML to Clojure? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I did the question "TwoSum" in ReasonML/Ocaml but I have no idea how to code that in Clojure with similar pseudo algorithm. Please comment how to translate this solution to Clojure
Clojure
(def nums [2 7 11 15])
(def target 9)
(defn two-sum [n xs]
(let [ixs (map vector xs (range (count xs)))]))
ReasonML
module TwoSum: {
let twoSum: (int, Belt.List.t(int)) => list(list(int));
let run: unit => unit;
} = {
let logl = l => l |> Array.of_list |> Js.log;
let concatmap = (xs: list('a), f) => {
List.concat(List.map(x => f(x), xs));
};
let twoSum = (n, xs) => {
let ixs = Belt.List.zip([0, ...range(1, List.length(xs))], xs);
concatmap(ixs, ((i, x)) =>
concatmap(drop(i, ixs), ((j, y)) => x + y == n ? [[i, j]] : [])
);
};
let run = () => {
Printf.printf("1. Two Sum :\n");
let res = twoSum(21, [0, 2, 11, 19, 90, 10]);
res |> logl;
};
};
You can use for to list all the possible index pairs and the :when option to filter pairs that fulfill the two-sum conditions. This will return a sequence of possible solutions. Then you pick the first solution.
(defn two-sum [numbers target]
(let [inds (range (count numbers))]
(first (for [i inds
j inds
:when (and (not= i j)
(= target (+ (nth numbers i)
(nth numbers j)))) ]
[i j]))))
(two-sum [2 7 11 15] 9)
;; => [0 1]
As a slight variation, I would use a helper function indexed to convert [:a :b :c] into:
[[0 :a]
[1 :b]
[2 :c]]
then we get:
(defn indexed
[vals]
(mapv vector (range) vals))
(defn two-sum
[vals tgt]
(let [idx-vals (indexed vals)]
(first
(for [[i x] idx-vals ; destructure each pair => local vars i & x
[j y] idx-vals
:when (and (< i j)
(= tgt (+ x y)))]
[i j]))))
and results
(two-sum [2 7 11 15] 666) => nil
(two-sum [2 7 11 15] 9) => [0 1]
(two-sum [0 1 2 7 11 15] 9) => [2 3]
i would go with more functional style:
starting from creating pairs function:
(defn pairs [data]
(->> data
(iterate rest)
(take-while seq)
(mapcat (fn [[x & xs]] (map (partial vector x) xs)))))
user> (pairs [:a :b :c :d])
;;=> ([:a :b] [:a :c] [:a :d] [:b :c] [:b :d] [:c :d])
then you can generate those pairs of index-to-item tuples:
user> (pairs (map-indexed vector [:a :b :c]))
;;=> ([[0 :a] [1 :b]]
;; [[0 :a] [2 :c]]
;; [[1 :b] [2 :c]])
so that you just need to keep the pairs you need:
(defn sum2 [target data]
(->> data
(map-indexed vector)
pairs
(keep (fn [[[i x] [j y]]]
(when (== target (+ x y))
[i j])))))
user> (sum2 9 [2 7 11 15])
;;=> ([0 1])
another option is to use list comprehensions for that:
(defn sum2 [target data]
(for [[[i x] & xs] (->> data
(map-indexed vector)
(iterate rest)
(take-while seq))
[j y] xs
:when (== target (+ x y))]
[i j]))
user> (sum2 9 [2 7 11 15])
;;=> ([0 1])

Debugging thread macro -> or ->> in Clojure

I want to understand how works the following code that is designed for the problem: "Given a sequence of integers, find a continuous subsequence which maximizes the sum of its elements"
defn max-subseq-sum [coll]
(->> (take-while seq (iterate rest coll)) ; tails (1)
(mapcat #(reductions conj [] %)) ; inits (2)
(apply max-key #(reduce + %)))) ; max sum
so I'd like to see the output of forms (1), (2) and others. I can set breakpoints in Cursive but yet I don't know how to get these values.
I have tried to define a locale variables, for example
(defn max-subseq-sum [coll]
(->> (take-while seq (iterate rest coll)) ; tails
(let [d #(reductions conj [] %)]
d ) ; inits
(apply max-key #(reduce + %)))
)
(max-subseq-sum [-1, -2, 3, 5, 6, -2, -1, 4, -4, 2, -1])
But i still don't understand how to see d, for example
How to solve this problem?
A simple function that prints and returns its input can be inserted into the chain:
(defn debug [x]
(println x)
x)
(defn max-subseq-sum [coll]
(->> (take-while seq (iterate rest coll))
(debug)
(mapcat #(reductions conj [] %))
(apply max-key #(reduce + %))))
(max-subseq-sum [-1, -2, 3, 5, 6, -2, -1, 4, -4, 2, -1])
([-1 -2 3 5 6 -2 -1 4 -4 2 -1] (-2 3 5 6 -2 -1 4 -4 2 -1) (3 5 6 -2 -1 4 -4 2 -1) (5 6 -2 -1 4 -4 2 -1) (6 -2 -1 4 -4 2 -1) (-2 -1 4 -4 2 -1) (-1 4 -4 2 -1) (4 -4 2 -1) (-4 2 -1) (2 -1) (-1))
=> [3 5 6 -2 -1 4]
Or, if you want better tracking and don't mind a bit of bulk, you can use a macro that includes the expression in the printout:
(defmacro debugM [expr]
`(let [x# ~expr] ; Save the result of the expression so it isn't evaluated twice
(println '~expr "\n\t" x#)
x#))
(defn max-subseq-sum [coll]
(->> (take-while seq (iterate rest coll))
(debugM)
(mapcat #(reductions conj [] %))
(apply max-key #(reduce + %))))
(max-subseq-sum [-1, -2, 3, 5, 6, -2, -1, 4, -4, 2, -1])
(take-while seq (iterate rest coll))
([-1 -2 3 5 6 -2 -1 4 -4 2 -1] (-2 3 5 6 -2 -1 4 -4 2 -1) (3 5 6 -2 -1 4 -4 2 -1) (5 6 -2 -1 4 -4 2 -1) (6 -2 -1 4 -4 2 -1) (-2 -1 4 -4 2 -1) (-1 4 -4 2 -1) (4 -4 2 -1) (-4 2 -1) (2 -1) (-1))
=> [3 5 6 -2 -1 4]
There is a nice library called debux
(use '[debux.core])
(defn max-subseq-sum [coll]
(dbg (->> (take-while seq (iterate rest coll)) ; tails (1)
(mapcat #(reductions conj [] %)) ; inits (2)
(apply max-key #(reduce + %)))))
(max-subseq-sum [1 2 3])
dbg: (->> (take-while seq (iterate rest coll)) (mapcat (fn* [p1__1991#] (re ... =>
| (take-while seq (iterate rest coll)) =>
| ([1 2 3] (2 3) (3))
| (mapcat (fn* [p1__1991#] (reductions conj [] p1__1991#))) =>
| ([] [1] [1 2] [1 2 3] [] [2] [2 3] [] [3])
| (apply max-key (fn* [p1__1992#] (reduce + p1__1992#))) =>
| [1 2 3]
I could do by injecting ((fn [x] (println x) x)).
(->> [1 2 3 4 5]
(filter even?)
((fn [x] (println x) x))
first)
that shows
(2 4)
2

How do I use a treemap for a 2 dimensional keys?

I want to map a large number of tuples. My map looks something like:
{[1 2] :thing}
Except there may be a few million of them. I have a feeling that a tree-map might be a good thing to test so I'm trying to get it working. I can't seem to get the comparison function right though.
(defn compare
[[x y] [xx yy]]
(cond
(and (= x xx) (= y yy)) 0
(and (<= x xx) (<= y yy)) -1
(and (<= x xx) (> y yy)) -1
(and (> x xx) (<= y yy)) 1
(and (> x xx) (> y yy)) 1))
Some trivial inputs seem to work
user=> (compare [1 1] [1 1])
0
user=> (compare [1 1] [2 2])
-1
user=> (compare [1 2] [2 1])
-1
user=> (compare [2 1] [1 2])
1
But if I create inputs that cover all combinations, the map should consider them all different.
(def inputs
"All tuples of [0-4, 5-10]."
(clojure.math.combinatorics/cartesian-product
(range 0 4)
(range 5 10)))
(def input-pairs
"All possible pairs of tuples"
(clojure.math.combinatorics/cartesian-product inputs inputs))
If I test the comparison function, it returns zero only when the two vectors are structurally identical.
user=> (doseq [[a b] input-pairs]
#_=> (when (zero? (compare a b)) (prn a b)))
(0 5) (0 5)
(0 6) (0 6)
(0 7) (0 7)
(0 8) (0 8)
(0 9) (0 9)
(1 5) (1 5)
etc
So I think my compare function is correct. Using it in the treemap, however, gives some strange results:
(def inputs-kvs
"Inputs in the format that the hash-map and sorted-map constructor understand"
(mapcat #(vector % (apply str %))
(clojure.math.combinatorics/cartesian-product
(range 0 4)
(range 5 10))))
Putting these in a hashmap gives the correct answer
(count (apply assoc (hash-map) inputs-kvs))
=> 20
But putting them in the treemap with the given comparison:
(def structure (sorted-map-by compare))
(count (apply assoc structure inputs-kvs))
=> 4
(apply assoc structure inputs-kvs)
=> {(0 5) "25", (1 6) "36", (2 7) "37", (3 5) "39"}
"25" has been stored in the (0 5) slot. But the compare function doesn't say that (0 5) and (2 5) are the same:
=> (compare [0 5] [2 5])
-1
What am I doing wrong? Can I make this work? Is it even meaningful to project a 2-dimensional space onto a 1-dimensional one?
(To head off a question you may have, yes I've tried a 2-dimensional structure, e.g. (sorted-map 1 (sorted-map 2 :value)), but I'm trying to find alternatives with better performance)
Clojure already comes with it's own compare:
user=> (doc compare)
-------------------------
clojure.core/compare
([x y])
Comparator. Returns a negative number, zero, or a positive number
when x is logically 'less than', 'equal to', or 'greater than'
y. Same as Java x.compareTo(y) except it also works for nil, and
compares numbers and collections in a type-independent manner. x
must implement Comparable
Which behaves the same as OPs own function, but most likely is more efficient:
user=> (compare [1 1] [1 1])
0
user=> (compare [1 1] [2 2])
-1
user=> (compare [2 1] [1 2])
1
The behaviour is documented in the Section about Vectors (IPersistentVector) in the Data Structures docs:
Vectors are compared first by length, then each element is compared in order.
So you can just use sorted-map-by compare from core, or since that's the default anyway just sorted-map for your data structure:
user=> (def m (into {} (let [r #(- (rand-int 10) (rand-int 10))] (for [a (range -1 2) b (range -1 2)] [[(r) (r)] (str a b)]))))
#'user/m
user=> (>pprint m)
{[-7 -4] "10",
[-3 5] "01",
[-5 -7] "00",
[5 2] "11",
[-3 1] "-10",
[7 -4] "-11",
[0 -6] "0-1",
[3 1] "-1-1",
[-8 -1] "1-1"}
nil
user=> (>pprint (into (sorted-map-by compare) m))
{[-8 -1] "1-1",
[-7 -4] "10",
[-5 -7] "00",
[-3 1] "-10",
[-3 5] "01",
[0 -6] "0-1",
[3 1] "-1-1",
[5 2] "11",
[7 -4] "-11"}
nil
user=> (>pprint (into (sorted-map) m))
{[-8 -1] "1-1",
[-7 -4] "10",
[-5 -7] "00",
[-3 1] "-10",
[-3 5] "01",
[0 -6] "0-1",
[3 1] "-1-1",
[5 2] "11",
[7 -4] "-11"}
nil
user=> (assert (= (into (sorted-map-by compare) m) (into (sorted-map) m)))
nil
I just added (vec %) to keep the tuples vectors - should not change anything.
As you can see it works here.
Might it be you have a some older REPL stuff laying around - especially since you alias clojure.core/compare ?
; using your compare function
(def inp (mapcat #(vector (vec %) (apply str %))
(clojure.math.combinatorics/cartesian-product (range 0 4) (range 5 10))))
; => ([0 5] "05" [0 6] "06" [0 7] "07" [0 8] "08" ...
(count inp)
; => 40
(apply assoc structure inp)
; => {[0 9] "09", [0 8] "08", [0 7] "07", [0 6] "06", ....
(count (apply assoc structure inp))
; => 20

Update Submatrix in Larger Matrix in Clojure

How can I update a large matrix, represented as nested vectors, by inserting a smaller submatrix at a particular position.
(def submatrix [[1 1] [1 1]])
(def matrix [[0 0 0] [0 0 0] [0 0 0]])
(def pos [1 1])
(defn update-matrix
"Returns new matrix with the submatrix inserted at the [x y] pos as
the top left position of the submatrix."
[matrix submatrix pos]
; implementation??
)
Desired output: (formatted for readability)
[[0 0 0]
[0 1 1]
[0 1 1]]
My progress so far:
I can update a subvector in a vector:
(def v [0 1 2 3 4 5 6])
(def subv ["x" "y" "z"])
(def pos 2)
(concat (take pos v) subv (drop (+ pos (count subv)) v)
; [0 1 "x" "y" "z" 5 6]
But I don't know where to go from here, or what might be most idiomatic.
Getting it right
We can define the required function as
(defn update-submatrix [m sub-m [x y]]
(replace-subvec
m
(map (fn [l r] (replace-subvec l r y)) (subvec m x) sub-m)
x))
... where (replace-subvec v s start) replaces the elements of vector v from index start with those of sequence s, as long as s lasts. For example,
(replace-subvec (vec (range 10)) (range 3) 5)
; [0 1 2 3 4 0 1 2 8 9]
A clear but slow implementation is
(defn replace-subvec [v s start]
(vec (concat (subvec v 0 start) s (subvec v (+ start (count s))))))
... giving, for the example in the question,
(def submatrix [[1 1] [1 1]])
(def matrix [[0 0 0] [0 0 0] [0 0 0]])
(def pos [1 1])
(update-submatrix matrix submatrix pos)
; [[0 0 0] [0 1 1] [0 1 1]]
Speeding it up
The key to speeding up update-submatrix is to speed up replace-subvec.
We can do so in two ways:
run through the altered elements by incrementing through a loop, and
use a transient collection within the function.
This gives us
(defn replace-subvec [v s start]
(loop [v (transient v), s s, i start]
(if (empty? s)
(persistent! v)
(recur (assoc! v i (first s)) (rest s) (inc i)))))
The effect is identical.
You can reduce over a sequence of update coordinates, at each step copying one item from the submatrix into the appropriate place in the larger matrix:
user> (defn update-matrix [matrix submatrix [y x]]
(reduce (fn [m [row col]]
(assoc-in m [(+ row y) (+ col x)]
(get-in submatrix [row col])))
matrix
(for [y (range (count submatrix))
x (range (count (first submatrix)))]
[y x])))
#'user/update-matrix
user> (update-matrix [[0 0 0] [0 0 0] [0 0 0]] [[1 1] [1 1]] [1 1])
[[0 0 0] [0 1 1] [0 1 1]]
Here's my 15 min. shot at it:
(defn update-matrix
"Returns new matrix with the submatrix inserted at the [x y] pos as
the top left position of the submatrix."
[matrix submatrix pos]
(let [[x y] pos
height (count submatrix)
width (count (get submatrix 0))]
(loop [i 0 m matrix]
(if (< i height)
(let [item (vec (concat (vec (drop-last width (get matrix x))) (get submatrix i)))]
(recur (+ 1 i) (assoc m (+ i y) item)))
m))))
Let me know if that doesn't work.

How to diff/substract two lists in Clojure

Example:
1 1 1 3 3 4 4 5 5 6 L1
1 3 3 4 5 L2
1 1 4 5 6 Res
Constraints:
The diff/subtract is defined as the "set" of elements from L1 minus (∖) L2
L2 is always a subset (⊆) of L1
The elements in L1 and L2 can have duplicates
The elements are primitives (int, string) and all of the same type
(clojure.set/difference) doesn't help here because of (3).
(defn diff [s1 s2]
(mapcat
(fn [[x n]] (repeat n x))
(apply merge-with - (map frequencies [s1 s2]))))
For example, given
(def L1 [1 1 1 3 3 4 4 5 5 6])
(def L2 [1 3 3 4 5 ])
then
(diff L1 L2)
;(1 1 4 5 6)
Here is one way to do it.
Steps:
1.Find the frequencies for each list
2.Diff the frequencies
3.Repeat each element for the remaining value of frequency.
(defn myminus [s1 s2]
(let [g1 (frequencies s1)
g2 (frequencies s2)
m (merge-with - g1 g2)
r (mapcat #(repeat (second %) (first %)) m)]
r))
If inputs are in order, as they appear to be, then you can do this lazily
(defn sdiff
[[x & rx :as xs] [y & ry :as ys]]
(lazy-seq
(cond
(empty? xs) nil
(empty? ys) xs
:else (case (compare x y)
-1 (cons x (sdiff rx ys))
0 (sdiff rx ry)
+1 (sdiff xs ry)))))
Given example:
(def L1 [1 1 1 3 3 4 4 5 5 6])
(def L2 [1 3 3 4 5])
(sdiff L1 L2) ;=> (1 1 4 5 6)
Lazy-sequence of numbers that are not Fibonacci numbers. (Notice we don't require constraint #2 -- the repeated 1's in the Fibonacci numbers do not cause a problem.)
(defn fibs [] (map first (iterate (fn [[c n]] [n (+ c n)]) [0 1])))
(take 20 (sdiff (range) (fibs)))
;=> (4 6 7 9 10 11 12 14 15 16 17 18 19 20 22 23 24 25 26 27)
Since L2 is always a subset of L1 you can group-by on both lists and just emit the key as many times as the difference is between the counts of each grouping.
(def L1 (list 1 1 1 3 3 4 4 5 5 6))
(def L2 (list 1 3 3 4 5 ))
(defn diff [l1 l2]
(let [a (group-by identity l1)
b (group-by identity l2)]
(mapcat #(repeat
(-
(count (second %))
(count (get b (key %))))
(key %)) a)))
(diff L1 L2)
;;(1 1 4 5 6)
(defn diff-subtract
"The diff-subtract is defined as the sum of elements from L1 minus L2"
[list1 list2]
(let [l1 (into {} (map #(vector (first %) %) (partition-by identity (sort list1))))
l2 (into {} (map #(vector (first %) %) (partition-by identity (sort list2))))]
(-> (map
#(repeat (- (count (l1 %)) (count (l2 %))) %)
(range 1 (inc (apply max (map first l1)))))
flatten)))
(diff-subtract [1 1 1 3 3 4 4 5 5 6] [1 3 3 4 5]) => (1 1 4 5 6)

Resources