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.
Related
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])
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]]
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
I have a sequence of integers and I would like to partition them into increasing segments and I want to have as little as possible segments. So I want to have
(segmentize [1 2 3 4 3 8 9 1 7] <=)
;=> [[1 2 3 4][3 8 9][1 7]]
I have implemented segmentize as follows:
(defn segmentize [col lte]
(loop [col col s [] res []]
(cond (empty? col) (conj res s)
(empty? s) (recur (rest col) (conj s (first col)) res)
(lte (last s) (first col)) (recur (rest col) (conj s (first col)) res)
:else (recur col [] (conj res s)))))
But I was wondering if there is already some handy clojure function that does exactly this, or if there is a more idiomatic way to do this.
You can build this with partition-by
(defn segmentize [cmp coll]
(let [switch (reductions = true (map cmp coll (rest coll)))]
(map (partial map first) (partition-by second (map list coll switch)))))
(segmentize <= [1 2 3 4 3 8 9 1 7])
;=> ((1 2 3 4) (3 8 9) (1 7))
The first two maps of the last line may be changed to mapv if you really want vectors rather than lazy sequences.
Another lazy implementation. Basically find out how many consecutive pairs of numbers return true for the "lte" function (take-while + segment) and then split the original collection by that number. Repeat with the reminder collection:
(defn segmentize
[coll lte]
(lazy-seq
(when-let [s (seq coll)]
(let [pairs-in-segment (take-while (fn [[a b]] (lte a b)) (partition 2 1 s))
[segment reminder] (split-at (inc (count pairs-in-segment)) s)]
(cons segment
(segmentize reminder lte))))))
This is a special case of some of the sequence-handling functions in org.flatland/useful, specifically flatland.useful.seq/partition-between:
(partition-between (partial apply >) xs)
If you require a from-scratch implementation with no external dependencies, I'd prefer dAni's answer.
Here is my version of segmentize (I called in split-when):
(defn split-when [f s]
(reduce (fn [acc [a b]]
(if (f b a)
(conj acc [b])
(update-in acc [(dec (count acc))] conj b)))
[[(first s)]]
(partition 2 1 s)))
(split-when < [1 2 3 4 3 8 9 1 7])
;; [[1 2 3 4] [3 8 9] [1 7]]
Because everybody loves lazy sequences:
(defn segmentize [coll cmp]
(if-let [c (seq coll)]
(lazy-seq
(let [[seg rem] (reduce (fn [[head tail] x]
(if (cmp (last head) x)
[(conj head x) (next tail)]
(reduced [head tail])))
[(vec (take 1 c)) (drop 1 c)]
(drop 1 c))]
(cons seg (segmentize rem cmp))))))
The code to compute each segment could probably be made a little less verbose using loop/recur, but I tend to find reduce more readable most of the time.
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)