Create 2-dimensional vectors from 1-dimensionals - clojure

Although my question seems to be concerned with a rather trivial task, I was not yet able to sucessfully create a single 2-dimensional vector
[[1 2] [3 4]]
fom two individual vectors,
(def a [1 2]) and (def b [3 4]).
Leaving the functions conj and cons aside, I ran into the problem that vec or into-array both expect single input values.
Another workaround would be pre-filling a two dimenstional vector
(vec (replicate 2 (vec (replicate 2 nil))))
but I it is still a complicated option.

Just use vector:
(def a [1 2])
(def b [3 4])
(vector a b) => [[1 2] [3 4]]
[a b] => [[1 2] [3 4]]

There are several ways to approach this:
As #MartinPůda says, use vector: (vector a b) => [[1 2] [3 4]])
Use conj: (conj [] a b) => [[1 2] [3 4]]
Use a vector literal: [a b] => [[1 2] [3 4]]
If Clojure has a problem it is an excess of riches. :-)

Related

How do I iterate through two Sets in Clojure in order to return their Cartesian product?

So I take in two Sets and wanna iterate through them in order to return a new set containing the cross product of the two sets.
(defn cartesian
"computes Cartesian product of A and B"
[A B]
use "set", "for")
I'm very new to Clojure so I'm not sure why use "set, "for" is included at all.
But A and B will be Sets. Now I wanna iterate through each one and return the Cartesian product of them. Example:
(cartesian #{1 2} #{3 4 5}) => #{[1 3] [1 4] [1 5] [2 3] [2 4] [2 5]}
I'm not sure on the steps to get there though. I have looked through documentation etc but can't find what I'm looking for. Other answer to this deal with lists etc. But I have to use 2 Sets.
What I'm looking at atm is using doseq[e A] and inside that doseq[x B] then add each vector-pair [e x] to a new Set and then return it. This doesn't seem like a standard functional solution though. Am I on the right track? How do I add it to a new Set?
You can accomplish that using for:
(defn cartesian [A B]
(set (for [a A
b B]
[a b])))
(cartesian #{1 2} #{3 4 5})
;; => #{[2 3] [2 5] [1 4] [1 3] [1 5] [2 4]}
Use cartesian-product from clojure.math.combinatorics. To get exact result you want (set of vectors), use into with map transducer:
(into #{} (map vec) (clojure.math.combinatorics/cartesian-product #{1 2} #{3 4 5}))
=> #{[2 3] [2 5] [1 4] [1 3] [1 5] [2 4]}

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]]

Return all elements from a list

I have a function
(defn my-fn [a b & args]
[a
(for [arg args]
(into [] (butlast arg)))
b])
If I do (my-fn [1 2] [3 4] [5 6 2] [7 8 3])
It returns [[1 2] ([5 6] [7 8]) [3 4]]
I want the output to be [[1 2] [5 6] [7 8] [3 4]] but I cannot figure out how to do this
Any help would be much appreciated.
I'd into [a] all your mapped values and then conj b at the end. E.g.
(defn my-fn [a b & args]
(-> [a]
(into (map (comp vec butlast) args))
(conj b)))
and one more variant, using quote and unquote splicing:
user> (defn my-fn2 [a b & args]
`[~a ~#(map (comp vec butlast) args) ~b])
;;=> #'user/my-fn2
user> (my-fn2 [1 2] [3 4] [5 6 2] [7 8 3])
;;=> [[1 2] [5 6] [7 8] [3 4]]
Your for statement returns a list.
(defn my-fn [a b & args]
(->> [[a]
(map (comp vec butlast) args)
[b]]
(apply concat)
vec))
The final vec transform your seq into a vector.
Here is one solution:
(defn my-fn [a b & args]
(vec
(concat
[a]
(for [arg args]
(into [] (butlast arg)))
[b])))
(my-fn [1 2] [3 4] [5 6 2] [7 8 3])
=> [[1 2] [5 6] [7 8] [3 4]]
Please note that concat returns a lazy list, which for larger and/or more complicated problems can cause a StackOverflowException. The outer vec converts the lazy list in to a concrete vector. It is unnecessary for this example and you could remove it if you want.
As another note, concat expects each argument to be a list/vector, so I have wrapped a and b into 1-element vectors. The output of for is already a (lazy) list.
Because conj, cons, concat, etc can be somewhat non-intuitive in their behavior, you may wish to checkout the helper functions glue, append, prepend, & friends in the Tupelo library.
Background
Suppose we have a mixture of scalars & vectors (or lists) that we want to combine into a single vector. We want a function ??? to give us the following result:
(??? 1 2 3 [4 5 6] 7 8 9) => [1 2 3 4 5 6 7 8 9]
Clojure doesn’t have a function for this. Instead we need to wrap all of the scalars into vectors and then use glue or concat:
; can wrap individually or in groups
(glue [1 2 3] [4 5 6] [7 8 9]) => [1 2 3 4 5 6 7 8 9] ; could also use concat
(glue [1] [2] [3] [4 5 6] [7] [8] [9]) => [1 2 3 4 5 6 7 8 9] ; could also use concat
It may be inconvenient to always wrap the scalar values into vectors just to combine them with an occasional vector value. Instead, it might be more convenient to unwrap the vector values, then combine the result with other scalars. We can do that with the ->vector and unwrap functions:
(->vector 1 2 3 4 5 6 7 8 9) => [1 2 3 4 5 6 7 8 9]
(->vector 1 (unwrap [2 3 4 5 6 7 8]) 9) => [1 2 3 4 5 6 7 8 9]
It will also work recursively for nested unwrap calls:
(->vector 1 (unwrap [2 3 (unwrap [4 5 6]) 7 8]) 9) => [1 2 3 4 5 6 7 8 9]
Alternate Solution Using Python-Style Generator Functions
You could also solve it this way:
(ns tst.clj.core
(:use clj.core tupelo.test)
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(defn my-fn [a b & args]
(lazy-gen
(yield a)
(yield-all (for [arg args]
(into [] (butlast arg))))
(yield b)))
(my-fn [1 2] [3 4] [5 6 2] [7 8 3]) => ([1 2] [5 6] [7 8] [3 4])
Here lazy-gen creates a context for a "generator function", where successive values are added to the output list using the yield and yield-all functions. Note that the yield-all function is like the Clojure "unquote-splicing" operator ~# and "unwraps" its sequence into the output stream.
An even easier answer is to dive deeper into the for part of your original solution to apply the yield output tap:
(defn my-fn2 [a b & args]
(lazy-gen
(yield a)
(doseq [arg args]
(yield (butlast arg)))
(yield b)))
(my-fn2 [1 2] [3 4] [5 6 2] [7 8 3]) => ([1 2] (5 6) (7 8) [3 4])
This version of the solution follows your original logic more closely,
and avoids the accidental complexity of the for function wrapping its results into a sequence, which conflicts with the a and b values not being wrapped in a vector. We also no longer need the (into [] ...) part of the original function.
Note that we have replaced the for with doseq since:
We are no longer using the return value of the loop
And, therefore, a lazy solution would never run

Clojure - Splitting a vector

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]]

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])