Clojure - Splitting a vector - clojure

If I have two arguments [[1 2] [3 4]] and [5 6], how can I get to [[1 5] [2 6] [3 5] [4 6]].
I thought I may have to use for so I tried,
(for [x [[1 2] [3 4]]]
(for [xx x]
(for [y [5 6]] [xx y])))
But it returned ((([1 5] [1 6]) ([2 5] [2 6])) (([3 5] [3 6]) ([4 5] [4 6])))
Any help would be much appreciated. Thanks

(mapcat #(map vector % [5 6]) [[1 2] [3 4]])
or using for:
(for [c [[1 2] [3 4]]
p (map vector c [5 6])]
p)

If I understood your question correctly, your solution is actually very close. You did not need to nest the for expressions explicitly, since doing so creates a new list at every level, instead, just use multiple bindings:
(for [x [[1 2][3 4]]
xx x
y [5 6]]
[xx y])
Which will result in
([1 5] [1 6] [2 5] [2 6] [3 5] [3 6] [4 5] [4 6])
Edit
Now that I finally read your question carefully, I came up with the same answer as #Lee did (mapcat (fn[x] (map vector x [5 6])) [[1 2] [3 4]]), which is the right one and should probably be accepted.

This is one (hmm - not particularly elegant) way to get your answer, without using for:
(defn f [x y]
(let [x' (apply concat x)
multiples (/ (count x') (count y))
y' (apply concat (repeat multiples y))]
(mapv vector x' y')))
(f [[1 2] [3 4]] [5 6])
;;=> [[1 5] [2 6] [3 5] [4 6]]

Related

Map all elements, preserving vector structures

For example, how could I best achieve this transformation:
[[[1 2]] [3 4] [[5] 6]] -> [[[2 3]] [4 5] [[6] 7]]
Is there an idiomatic way of doing this, with any number of levels?
You could use clojure.walk to increment numbers in arbitrarily nested structures:
(def data [[[1 2]] [3 4] [[5] 6]])
(clojure.walk/postwalk
#(if (number? %) (inc %) %)
data)
=> [[[2 3]] [4 5] [[6] 7]]

Clojure - Applying a Function to a vector of vectors

I have a vector [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]. I want to apply a function to this vector but keep the data structure.
For example I want to add 1 to every number but keep the data structure to get the result being [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]. Is this possible?
I have tried
(map #(+ 1 %) (flatten [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]))
=> (2 3 4 5 6 7 8 9 10 11 12)
But you can see that the data structure is not the same.
Is there maybe a function that takes (2 3 4 5 6 7 8 9 10 11 12) to [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]
I thought maybe to use postwalk but I'm not sure if this is correct.
Any help would be much appreciated
You can use postwalk:
(require '[clojure.walk :as walk])
(let [t [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]]
(walk/postwalk (fn [x] (if (number? x) (inc x) x)) t))
also the classic recursive solution is not much more difficult:
(defn inc-rec [data]
(mapv #((if (vector? %) inc-rec inc) %) data))
#'user/inc-rec
user> (inc-rec [1 [2 3 [4 5] [6 7]] [[8 9] 10]])
;;=> [2 [3 4 [5 6] [7 8]] [[9 10] 11]]
Another way to solve your problem is via Specter. You do need another dependency then, but it can be a helpful library.
(ns your-ns.core
(:require [com.rpl.specter :as specter]))
(def data [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11])
(specter/defprotocolpath TreeWalker) ;; define path walker
(specter/extend-protocolpath TreeWalker
;; stop walking on leafs (in this case long)
Object nil
;; when we are dealing with a vector, TreeWalk all elements
clojure.lang.PersistentVector [specter/ALL TreeWalker])
You can extend it to perform more complicated operations. For this use case normal Clojure is good enough.
(specter/transform [TreeWalker] inc data)
;; => [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]

Clojure - Combining Two vectors into a vector of vectors [duplicate]

This question already has answers here:
Clojure - Splitting a vector
(3 answers)
Closed 5 years ago.
How can I combine [[1 2] [3 4]] and [5 6] to get [[1 5] [2 5] [3 6] [4 6]]
I tried (map vector [[1 2] [3 4]] [5 6]) but the result was ([[1 2] 5] [[3 4] 6])
Any help would be much appreciated. Thanks
You can use mapcat and an inner map like this:
user=> (mapcat (fn [as b]
(mapv #(vector % b) as))
[[1 2] [3 4]] [5 6])
([1 5] [2 5] [3 6] [4 6])

Combine sequence with itself recursively, without duplicates

This is hard to explain but easy to show. Not sure why I haven't figured it out myself, so I must be missing something in clojure that is obvious.
I need to combine a vector with itself, into a vector, and I need to combine the first element with all the remaining elements, then the 2nd element, with all the remaining elements (3rd and after).
As a short example:
[1 2 3 4 5]
I need a function to get:
[[1 2] [1 3] [1 4] [1 5] [2 3] [2 4] [2 5] [3 4] [3 5]]
If this looks like getting half the pairs for a large matrix, you are right. I only want to solve half the matrix minus the middle diagonal. This is the only part I need to be sequential(so I only solve half) and the rest I want to use the reducers library to parallelize the heavier math in the background.
Thanks in advance!
What you want is built into clojure/math.combinatorics:
https://github.com/clojure/math.combinatorics
The basic example you are looking for is on the readme, but for completeness to this answer, I'll repeat it here:
(ns example.core
(:require [clojure.math.combinatorics :as combo]))
(combo/combinations [1 2 3] 2)
;;=> ((1 2) (1 3) (2 3))
I'd just use a for :
(for [ i (range 1 6) j (range 6) :when (< i j)] [i j])
; => ([1 2] [1 3] [1 4] [1 5] [2 3] [2 4] [2 5] [3 4] [3 5] [4 5])
(def v [1 2 3 4 5])
(for [i (range (count v))
:let [vv (drop i v)]
r (rest vv)]
[(first vv) r])
=> ([1 2] [1 3] [1 4] [1 5] [2 3] [2 4] [2 5] [3 4] [3 5] [4 5])

why does the output of core.logic give the same value repeated?

I tried this in core.logic
(require [clojure.core.logic :as l])
(l/run* [q]
(l/fresh [a b c]
(l/membero a [1])
(l/membero b [4 5])
(l/membero c [1 2])
(l/== q [a b])))
expecting the result to be [1 4] [1 5]
but it was [1 4] [1 4] [1 5] [1 5]
then I started playing with it and found this:
(require [clojure.core.logic :as l])
(l/run* [q]
(l/fresh [a b c]
(l/membero a [1])
(l/membero b [4 5])
(l/membero c [1 1 1 1 1 1 1 1])
(l/== q [a b])))
;; => ([1 4] [1 4] [1 4] [1 5] [1 4] [1 4] [1 5] [1 4] [1 5] [1 4] [1 5] [1 5] [1 5] [1 5])
where there is a [1 5] interspersed with [1 4]
what is happening? is this repetition thing supposed to be a feature or a bug?
This is because the usage of the logic variable c which is not required as it is not being unified with q. If you remove c then you will get desired result. Basically you need to understand how the substitution works in core.logic to understand why you are getting these duplicate results because of c.
At a high level the process is like searching a tree for solutions, in this case each element in the vector which is membero with c leads to a node in the search tree and that causes duplicate results because for each node introduced by c probable values leads to correct result as c isn't used in the unification (l/== q [a b])