I'm trying to understand the syntax of this cartesian-product function in Clojure - syntax

Here's some code for a cartesian product, it can be two lists, two vectors, or any number of combinations of the two. I'd really appreciate help with the second, fourth, and final lines, explaining what each line is doing
(defn cartesian-product ;function name definition
([] '(())) ;need help understanding this
([xs & more] ; at least two variables, xs is one of them
(mapcat #(map (partial cons %) ;mapcat means a create a concatenated map of the following
;still trying to figure out partial, but cons takes a
;variable and puts it in front of a sequence
(apply cartesian-product more)) ; this is the sequence that is mapped
; using (partial cons %)
xs))) ;not sure what this is here for

Here is a reworked version that illustrates what is going on (and how):
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
;----------------------------------------------------------------------------
; Lesson: how map & mapcat work
(defn dup [x]
"Return 2 of the arg in a vector"
[x x])
(dotest
(let [nums [0 1 2]]
(is= (mapv inc nums) [1 2 3])
(is= (mapv dup nums) [[0 0] ; like a matrix, 2-D
[1 1]
[2 2]])
; mapcat glues together the inner "row" vectors. So the result is 1-D instead of 2-D
(is= (mapcat dup nums) [0 0 1 1 2 2])))
then the reworked code
;----------------------------------------------------------------------------
(def empty-matrix [[]]) ; 0 rows, 0 cols
(defn cartesian-product ;function name definition
"When called with 1 or more sequences, returns a list of all possible combinations
of one item from each collection"
([] ; if called with no args
empty-matrix) ; return an empty matrix
; if called with 1 or more args,
([xs ; first arg is named `xs` (i.e. plural for x values)
& more] ; all other args are wrapped in a list named `more`
(let [recursion-result (apply cartesian-product more) ; get cartesian prod of sequences 2..N
inner-fn (fn [arg] (map ; for each recursion-result
(partial cons arg) ; glue arg to the front of it
recursion-result))
; for each item in the first sequence (xs), glue to front of
; each recursion result and then convert 2D->1D
output (mapcat inner-fn xs)]
output)))
and some unit tests to show it in action
(dotest
(is= (cartesian-product [1 2 3]) [[1] [2] [3]])
(is= (cartesian-product [1 2 3] [:a :b])
[[1 :a]
[1 :b]
[2 :a]
[2 :b]
[3 :a]
[3 :b]])
(is= (cartesian-product [1 2 3] [:a :b] ["apple" "pea"])
[[1 :a "apple"]
[1 :a "pea"]
[1 :b "apple"]
[1 :b "pea"]
[2 :a "apple"]
[2 :a "pea"]
[2 :b "apple"]
[2 :b "pea"]
[3 :a "apple"]
[3 :a "pea"]
[3 :b "apple"]
[3 :b "pea"]]))

Related

clojure.lang.LazySeq cannot be cast to clojure.lang.IFn nested for loops clojure

i'm new to clojure and functional programming so i would appreciate some help. :)
What i'm trying to do is : I'm trying to get this
[1 1 2] from this "structure" [[1 0 1] [0 1 0] [0 0 1]] therefore i'm trying to sum first elements of the three vectors, second elements of the three vectors and finally third elements of the three vectors to get a new vector in the end containing this sums.
My code is the following:
(def matrix [[1 0 1] [0 1 0] [0 0 1]])
(def sum (atom 0))
(def sum-vector (atom []))
(for [i (range 3)]
((for [j (range (count matrix))]
(reset! sum (+ #sum (nth (nth matrix j) i)))
)
(reset! sum-vector (conj #sum-vector #sum))
(reset! sum 0)
))
But i get this exception : clojure.lang.LazySeq cannot be cast to clojure.lang.IFn ... What i'm i doing wrong?
The problem is ((for ....)) That says evaluate the (for ....) form, and then take that result and execute it. The (for ...) is returning a LazySeq, instead of a function.
(apply map + [[1 0 1] [0 1 0] [0 0 1]])
;; (1 1 2)
If you want a vector returned instead of a LazySeq:
(apply mapv + [[1 0 1] [0 1 0] [0 0 1]])
;; [1 1 2]

Update matrix in-place in Clojure

Suppose I have a Clojure matrix A as such (formatted for clarity)
[[1 4 3]
[1 7 3]
[1 8 3]]
Now suppose I want to update the first column in place, by e.g. multiplying it by a factor of two, so that the new matrix becomes
[[2 4 3]
[2 2 3]
[2 8 3]]
How would one do this in clojure? I have tried things like assoc and stuff like
(join-along 1 (* (slice A 1 0) 2) (select A [0 1 2] [2 3]))
Naturally that did not work. It would be great if there was something like assoc for matrices e.g.
(massoc A [rows] [columns] replacement-vector)
or something simple like numpy in Python:
A[:,0]*2 = [[2 4 3]
[2 2 3]
[2 8 3]]
Thanks
You should look into clojure.core/matrix and see if it supports operations like this.
Here is something that may be what you're looking for. It should be trivial to change this to assoc a new value rather than updating after applying a function.
(defn mupdate-in
"Update all `coll' rows at `column' with `f'"
[coll column f & args]
(reduce #(apply update-in %1 [%2 column] f args)
coll
(range (count coll))))
An example:
(def m [[1 4 3]
[1 7 3]
[1 8 3]])
(mupdate-in m 0 * 2)
;; [[2 4 3]
;; [2 7 3]
;; [2 8 3]]
(mupdate-in m 2 + 10)
;; [[1 4 13]
;; [1 7 13]
;; [1 8 13]]

Clojure: I have many sorted maps and want to reduce in order all there values a super maps of keys -> vector

I have seen this but can't work out how to apply it (no pun intended) to my situation.
I have a sorted list of maps like this: (note there can be more than two keys in the map)
({name1 3, name2 7}, {name1 35, name2 7}, {name1 0, name2 3})
What I am after is this data structure afterwards:
({:name1 [3,35,0]}, {:name2 [7,7,3]})
Ive been struggling with this for a while and cant seem to get anywhere near.
Caveats: The data must stay sorted and I have N keywords not just two.
I'd go for merge-with with some preprocessing added:
(def maps [{:a :b :e :f} {:a :c} {:a :d :e :g}])
(apply merge-with concat (for [m maps [k v] m] {k [v]}))
>>> {:e (:f :g), :a (:b :c :d)}
I think the function you want is merge-with:
user=> (def x {:a 1 :b 2})
user=> (def y {:a 3 :b 4})
user=> (merge-with vector x y)
{:a [1 3], :b [2 4]}
user=>
user=> (def z {:a 5 :b 6 :c 7})
user=> (merge-with vector x y z)
{:a [[1 3] 5], :c 7, :b [[2 4] 6]} ; oops
user=> (merge-with #(vec (flatten (vector %1 %2))) x y z)
{:a [1 3 5] :b [2 4 6] :c 7}
user=>
This is my attempt at the problem. It is not as elegant as Rafal's solution.
(def maps [{:a :b :e :f} {:a :c} {:a :d :e :g}])
(apply merge-with #(if (list? %1) (conj %1 %2) (list %1 %2)) maps)
>>> {:a (:d :b :c), :e (:f :g)}

For loop in clojure

n = (count somevector)
(foo [w] ( for [i (range n)
j (range w)
:let [n (* i j)]
:while ( < i j)
]
(println n)))
When i run it.
=> (foo 10)
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IFn HelloWorld.core/foo
What I am really looking to do is have a couple of nested for loops and have some ifs and else inside it do some checking.
Edit ::
As it turns out the following also causes error
(defn foo [arg]
(
for [ i (range (count vector)) ]
(
for [j arg ]
[i j]
)
) )
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom
Edit::
the following works
(defn foo [arg]
(def w arg)
(for [ i (range (count vector)) ]
(
for [j (range v) ]
[i j]
)
) )
Now can someone help me understand why would it not work in the first place ?
if you use :while, for-loop will return null, because first value is false, :when is better.
user=> (for [i (range 3) j (range 5)] [i j])
([0 0] [0 1] [0 2] [0 3] [0 4] [1 0] [1 1] [1 2] [1 3] [1 4] [2 0] [2 1] [2 2] [2 3] [2 4])
user=> (for [i (range 3) j (range 5) :while (< i j)] [i j])
()
user=> (for [i (range 3) j (range 5) :when (< i j)] [i j])
([0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4])
Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom
This error message states the cause of exception accurately.
I guess you passed a long value where a seq is expected.
I could reproduce it:
user> (def v [1 2 3])
#'user/v
user> (defn foo [arg]
(for [ i (range (count v)) ]
(for [j arg ]
[i j])))
#'user/foo
user> (foo (range 3))
(([0 0] [0 1] [0 2]) ([1 0] [1 1] [1 2]) ([2 0] [2 1] [2 2]))
user> (foo 3)
; Evaluation aborted.
; Don't know how to create ISeq from: java.lang.Long
; [Thrown class java.lang.IllegalArgumentException]
Your foo function works. However, the arg argument must be a seq,
because arg is binded in the nested for to j
The first thing you should know is, that clojure's for is not a for loop, it's a list comprehension.
This means, that it is used to build lists (lazy sequence, actually) with the specified properties.
Your original for looks like this:
(for [i (range n)
j (range w)
:let [n (* i j)]
:while ( < i j)]
(println n))
(I don't get a class cast exception with your original example).
What it says is: take pairs of i and j while i < j do something. The first pair of i and j is i = 0 and j = 0. Is 0 < 0? No. Stop. That is, you're constructing an empty sequence.
Now, if we change the :while with :when, it'll change the meaning to: for each pair of i and j, for which i < j, and do something with them. That is, you won't stop constructing the sequence when you encounter an i >= j, you'll just skip this pair.
The next thing to note is the println. This function prints its arguments, but always returns nil. This return value is what you'll get in the result sequence and the printing is called a side effect. Generally, you don't want side effect with lazy sequences, because they (the side effects) will happen when needed. That is, if you assign the returned sequence to some variable, none of the printlns will be called. They'll start popping up, when the sequence gets realized.
The bottom line is, don't think of for as a loop, think of it as a sequence constructor.

Implementing a counter in for

I would like to iterate over a collection and at the same time also maintain a counter ex
(for [x (range 10) y (inc 0)] [x y] )
I would like 'y' to represent the counter, so for every element the output is ( [0 0] [ 1 1] [2 2]...). How do I do that?
You can use indexed from clojure.contrib.seq. Example:
(indexed '(a b c d)) => ([0 a] [1 b] [2 c] [3 d])
You can also use map-indexed. Example:
(map-indexed vector "foobar") => ([0 \f] [1 \o] [2 \o] [3 \b] [4 \a] [5 \r])
Use map-indexed, as Simeon advices. In the for context it's convenient to use destructuring to get easy access to both the counter and the collection elements:
(for [ [y x] (map-indexed vector (range 10) ) ] [x y] )
> ([0 0] [1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9])
I figure if this question still had not been marked as "answered", there may be something else you are looking for, and perhaps it is the flexibility to define your own counter.
I agree with others that for the specific problem you outline, map-indexed is the way to go. However, if you insist on using for, I would recommend something like this:
(for [[x y] (map vector (range 10) (iterate inc 0))]
[x y])
Rafal has a very similar answer, except that the counter will always start from zero and increment by 1. In my version you could define your counter as you see fit. For example, by changing the above (iterate inc 0) to (iterate #(+ 2 %) 10), you could instead have a counter that starts at 10 and increments by 2.
(keep-indexed (fn [i el][el i]) (range 10))
or
(keep-indexed #(vec [%2 %1]) (range 10))
(keep-indexed #(identity [%2 %1]) (range 10))
;([0 0] [1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9])
Also, remember that using indexes in Clojure is generally a code smell.

Resources