Cartesian product in clojure - clojure

I'm trying to implement a method that will take a list of lists and return a the cartesian product of these lists.
Here's what I have so far:
(defn cart
([] '())
([l1] (map list l1))
([l1 l2]
(map
(fn f[x] (map
(fn g [y] (list x y))
l2))
l1)
)
)
(defn cartesian-product [& lists]
(reduce cart lists)
)
;test cases
(println (cartesian-product '(a b) '(c d))) ; ((a c) (a d) (b c) (b d))
(println (cartesian-product ())) ;()
(println (cartesian-product '(0 1))) ; ((0) (1))
(println (cartesian-product '(0 1) '(0 1))) ; ((0 0) (0 1) (1 0) (1 1))
(println (apply cartesian-product (take 4 (repeat (range 2))))) ;((0 0 0 0) (0 0 0 1) (0 0 1 0) (0 0 1 1) (0 1 0 0) (0 1 0 1) (0 1 1 0) (0 1 1 1) (1 0 0 0) (1 0 0 1) (1 0 1 0) (1 0 1 1) (1 1 0 0) (1 1 0 1) (1 1 1 0) (1 1 1 1))
The problem is my solution is really 'brackety'.
(((a c) (a d)) ((b c) (b d)))
()
(0 1)
(((0 0) (0 1)) ((1 0) (1 1)))
(((((((0 0) (0 1)) 0) (((0 0) (0 1)) 1)) 0) (((((0 0) (0 1)) 0) (((0 0) (0 1)) 1)) 1)) ((((((1 0) (1 1)) 0) (((1 0) (1 1)) 1)) 0) (((((1 0) (1 1)) 0) (((1 0) (1 1)) 1)) 1)))
I tried adding
(apply concat(reduce cart lists))
but then I get a crash like so:
((a c) (a d) (b c) (b d))
()
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:494)
So, I think I'm close but missing something. However since I'm so new to clojure and functional programming I could be on the completely wrong track. Please help! :)

This is a lot easier to do as a for-comprehension than by trying to work out the recursion manually:
(defn cart [colls]
(if (empty? colls)
'(())
(for [more (cart (rest colls))
x (first colls)]
(cons x more))))
user> (cart '((a b c) (1 2 3) (black white)))
((a 1 black) (a 1 white) (a 2 black) (a 2 white) (a 3 black) (a 3 white)
(b 1 black) (b 1 white) (b 2 black) (b 2 white) (b 3 black) (b 3 white)
(c 1 black) (c 1 white) (c 2 black) (c 2 white) (c 3 black) (c 3 white))
The base case is obvious (it needs to be a list containing the empty list, not the empty list itself, since there is one way to take a cartesian product of no lists). In the recursive case, you just iterate over each element x of the first collection, and then over each cartesian product of the rest of the lists, prepending the x you've chosen.
Note that it's important to write the two clauses of the for comprehension in this slightly unnatural order: swapping them results in a substantial slowdown. The reason for this is to avoid duplicating work. The body of the second binding will be evaluated once for each item in the first binding, which (if you wrote the clauses in the wrong order) would mean many wasted copies of the expensive recursive clause. If you wish to be extra careful, you can make it clear that the two clauses are independent, by instead writing:
(let [c1 (first colls)]
(for [more (cart (rest colls))
x c1]
(cons x more)))

I would check https://github.com/clojure/math.combinatorics it has
(combo/cartesian-product [1 2] [3 4])
;;=> ((1 3) (1 4) (2 3) (2 4))

For the sake of comparison, in the spirit of the original
(defn cart
([xs]
xs)
([xs ys]
(mapcat (fn [x] (map (fn [y] (list x y)) ys)) xs))
([xs ys & more]
(mapcat (fn [x] (map (fn [z] (cons x z)) (apply cart (cons ys more)))) xs)))
(cart '(a b c) '(d e f) '(g h i))
;=> ((a d g) (a d h) (a d i) (a e g) (a e h) (a e i) (a f g) (a f h) (a f i)
; (b d g) (b d h) (b d i) (b e g) (b e h) (b e i) (b f g) (b f h) (b f i)
; (c d g) (c d h) (c d i) (c e g) (c e h) (c e i) (c f g) (c f h) (c f i))

I know I'm late to the party -- I just wanted to add a different approach, for the sake of completeness.
Compared to amalloy's approach, it is lazy too (the parameter lists are eagerly evaluated, though) and slightly faster when all results are required (I tested them both with the demo code below), however it is prone to stack overflow (much like the underlying for comprehension it generates and evaluates) as the number of lists increases. Also, keep in mind that eval has a limit to the size of the code it can be passed to.
Consider first a single instance of the problem: You want to find the cartesian product of [:a :b :c] and '(1 2 3). The obvious solution is to use a for comprehension, like this:
(for [e1 [:a :b :c]
e2 '(1 2 3)]
(list e1 e2))
; ((:a 1) (:a 2) (:a 3) (:b 1) (:b 2) (:b 3) (:c 1) (:c 2) (:c 3))
Now, the question is: Is it possible to generalize this in a way that works with an arbitrary number of lists? The answer here is affirmative. This is what the following macro does:
(defmacro cart [& lists]
(let [syms (for [_ lists] (gensym))]
`(for [~#(mapcat list syms lists)]
(list ~#syms))))
(macroexpand-1 '(cart [:a :b :c] '(1 2 3)))
; (clojure.core/for [G__4356 [:a :b :c]
; G__4357 (quote (1 2 3))]
; (clojure.core/list G__4356 G__4357))
(cart [:a :b :c] '(1 2 3))
; ((:a 1) (:a 2) (:a 3) (:b 1) (:b 2) (:b 3) (:c 1) (:c 2) (:c 3))
Essentially, you have the compiler generate the appropriate for comprehension for you. Converting this to a function is pretty straightforward, but there is a small catch:
(defn cart [& lists]
(let [syms (for [_ lists] (gensym))]
(eval `(for [~#(mapcat #(list %1 `'~%2) syms lists)]
(list ~#syms)))))
(cart [:a :b :c] '(1 2 3))
; ((:a 1) (:a 2) (:a 3) (:b 1) (:b 2) (:b 3) (:c 1) (:c 2) (:c 3))
Lists that are left unquoted are treated as function calls, which is why quoting %2 is necessary here.
Online Demo:
; https://projecteuler.net/problem=205
(defn cart [& lists]
(let [syms (for [_ lists] (gensym))]
(eval `(for [~#(mapcat #(list %1 `'~%2) syms lists)]
(list ~#syms)))))
(defn project-euler-205 []
(let [rolls (fn [n d]
(->> (range 1 (inc d))
(repeat n)
(apply cart)
(map #(apply + %))
frequencies))
peter-rolls (rolls 9 4)
colin-rolls (rolls 6 6)
all-results (* (apply + (vals peter-rolls))
(apply + (vals colin-rolls)))
peter-wins (apply + (for [[pk pv] peter-rolls
[ck cv] colin-rolls
:when (> pk ck)]
(* pv cv)))]
(/ peter-wins all-results)))
(println (project-euler-205)) ; 48679795/84934656

Personally, I would use amalloy's for solution. My general rule of thumb is that if my loop can be expressed as a single map/filter/etc call with a simple function argument (so a function name or short fn/#() form), its better to use the function. As soon as it gets more complex than that, a for expression is far easier to read. In particular, for is far better than nested maps. That said, if I didn't use for here, this is how I'd write the function:
(defn cart
([] '(()))
([xs & more]
(mapcat #(map (partial cons %)
(apply cart more))
xs)))
Things to note: First, there's no need for the reduce. Recursion can handle it just fine.
Second, only two cases. We can call the function just fine on an empty list, so all we care about is empty vs non-empty.
Third, as amalloy explained, the correct value of (cart) is '(()). This is actually rather subtle, and I reliably mess this up when I write a function like this. If you walk through a simple case very carefully, you should be able to see why that value makes the recursion work.
Fourth, I generally don't like to use fn. This is more of a personal preference, but I always use #(), partial, or comp if I can get away with it. #() is definitely idiomatic for smaller functions, though the other two are a bit less common.
Fifth, some style notes. The biggest issue is indentation. The best suggestion here is to find an editor that auto-indents lisp code. Auto-indentation is one of the most important things for your editor to provide, since it makes it blindingly obvious when your parens don't match up. Also, closing parens never go on their own line, fns don't need internal names unless you are planning on recursing, and I generally have a few more newlines than you do. I like to think that my code above is reasonably decently styled, and as another example, here is how I would format your code:
(defn cart
([] '())
([l1] (map list l1))
([l1 l2]
(map (fn [x]
(map (fn [y]
(list x y))
l2))
l1)))
(defn cartesian-product [& lists]
(reduce cart lists))

For most purposes Alan's answer is great as you get a lazy comprehension, and a lazy seq will not cause a stack overflow as you realize its members, even if you do not use (recur).
I was interested in trying to craft the tail recursive version with explicit recur, not the least of which because laziness wasn't going to be of any help in my application, but also for fun and giggles:
(defn cartesian-product
([cols] (cartesian-product '([]) cols))
([samples cols]
(if (empty? cols)
samples
(recur (mapcat #(for [item (first cols)]
(conj % item)) samples)
(rest cols)))))

Related

Getting the most nested list in Clojure

I am migrating some LISP functions to Clojure. I have problems with StackOverflow message for the following functions:
(defn m
[list depth]
(cond
(= list nil) depth
(atom (first list)) (m (rest list) depth)
(> (m (first list) (+ depth 1)) (m (rest list) depth)) (m (first list) (+ depth 1))
:default (m (rest list) depth))
)
(defn n
[list depth maxdepth]
(cond
(= list nil) nil
(= depth maxdepth) list
(atom (first list)) (n (rest list) depth maxdepth)
(= 0 (n (first list) (+ depth 1) maxdepth)) (n (last list) depth maxdepth)
:default (n (first list) (+ depth 1) maxdepth))
)
(defn myfind[mylist]
(n mylist 0 (m mylist 0))
)
What I basically want is the output of the most nested list, as in:
(myfind '(1 2 3 (4 5) 6 ((7 8) 9)))
=> (7 8)
The goal is to use recursion and minimize the usage of builtin functions to achieve that.
What is wrong in this case?
(defn- deepest-with-depth [depth s]
(let [nested-colls (filter coll? s)]
(if (seq nested-colls)
(mapcat (partial deepest-with-depth (inc depth)) nested-colls)
[[depth s]])))
(defn deepest [s]
(->> (deepest-with-depth 0 s)
(apply max-key first)
second))
> (deepest '(1 2 3 (4 5) 6 ((7 8) 9)))
(7 8)
Feel free to subsitute some function calls (e.g. max-key, partial) with their implementations, if they conflict with your requirements.
here is one more variant, with just classic old school solution, and no clojure specific sequence functions at all:
(defn deepest [items depth]
(if (sequential? items)
(let [[it1 d1 :as res1] (deepest (first items) (inc depth))
[it2 d2 :as res2] (deepest (next items) depth)]
(cond (>= depth (max d1 d2)) [items depth]
(>= d1 d2) res1
:else res2))
[items -1]))
it is also notable by it's classic approach to the nested lists recursion: first you recur on car, then on cdr, and then combine these results.
user> (deepest '(1 2 3 (4 5) 6 ((7 8) 9)) 0)
[(7 8) 2]
user> (deepest '(1 2 3 (4 5) 6) 0)
[(4 5) 1]
user> (deepest '(1 2 3 (x ((y (z)))) (4 5) 6) 0)
[(z) 4]
user> (deepest '(1 2 3 (x ((y (z)))) (4 5 ((((((:xxx)))))))) 0)
[(:xxx) 7]
user> (deepest '(1 2 3 ((((((((nil)))))))) (x ((y (z)))) (4 5) 6) 0)
[(nil) 8]
user> (deepest '(1 2 3) 0)
[(1 2 3) 0]
(defn- max-depth-entry [a-list]
(let [sub-lists (filter coll? a-list)
[depth list] (if (empty? sub-lists)
[0 a-list]
(apply max-key first (map max-depth-entry sub-lists)))]
[(inc depth) list]))
(max-depth-entry '(1 2 3 (4 5) 6 ((7 8) 9)))
;[3 (7 8)]
Then
(def max-depth-sublist (comp second max-depth-entry))
(max-depth-sublist '(1 2 3 (4 5) 6 ((7 8) 9)))
;(7 8)
I owe the idea of using max-key to OlegTheCat's answer. I originally knitted my own, using reduce:
(defn- max-depth-entry [a-list]
(let [sub-lists (filter coll? a-list)
[a-list a-depth] (reduce
(fn ([] [a-list 0])
([[as an :as asn] [s n :as sn]] (if (> n an) sn asn)))
(map max-depth-entry sub-lists))]
[a-list (inc a-depth)]))
Then
(def max-depth-sublist (comp first max-depth-entry))
Now I'm ready to return to Sequs Horribilis on 4Clojure, which has stymied me until now.

Trapezoidal Integration is not accurate enough in Clojure

So currently, I wrote a Clojure code to do Trapezoidal integration of a polynomial function in HackerRank.com:
https://www.hackerrank.com/challenges/area-under-curves-and-volume-of-revolving-a-curv
(defn abs[x]
(max x (- 0 x))
)
(defn exp[x n]
(if (> n 0)
(* x (exp x (- n 1)))
1
)
)
(defn fact[x]
(if (> x 0)
(* x (fact (- x 1)))
1)
)
(defn func[x lst1 lst2]
((fn step [sum lst1 lst2]
(if (> (.size lst1) 0)
(step (+ sum (* (last lst1) (exp x (last lst2)))) (drop-last lst1) (drop-last lst2))
sum
)
)
0 lst1 lst2
)
)
(defn integrate[f a b]
(def h 0.001)
(def n (/ (abs (- b a)) h))
((fn step[i sum]
(if (< i n)
(step (+ i 1) (+ sum (f (+ (* i h) a))))
(* h (+ (/(+ (f a) (f b)) 2) sum))
)
) 0 0)
)
(defn volumeIntegral[f a b]
(defn area[r]
(* 3.14159265359 (* r r)))
(def h 0.001)
(def n (/ (abs (- b a)) h))
((fn step[i sum]
(if (< i n)
(step (+ i 1) (+ sum (area (f (+ (* i h) a)))))
(* h (+ (/ (+ (f a) (f b)) 2) sum))
)
) 0 0)
)
(defn lineToVec[line_str] (clojure.string/split line_str #"\s+"))
(defn strToDouble [x] (Double/parseDouble (apply str (filter #(Character/isDigit %) x))))
(defn readline[vec]
((fn step[list vec]
(if (> (.size vec) 0)
(step (conj list (last vec)) (drop-last vec))
list
)
) '() vec)
)
(integrate (fn [x] (func x '(1 2 3 4 5 6 7 8) '(-1 -2 -3 -4 1 2 3 4))) 1 2)
(volumeIntegral (fn [x] (func x '(1 2 3 4 5 6 7 8) '(-1 -2 -3 -4 1 2 3 4))) 1 2)
However, the output I have is:
107.38602491666647
45611.95754801859
While is supposed to be around:
101.4
41193.0
My code passed the first two test cases, but didn't manage to pass the rest. I assume is because of the issue accuracy. I looked through my code several times but couldn't seem to make it better. What am I doing wrong here ? Thank you.
Your exp function isn't quite right -- it doesn't handle negative exponents correctly. Probably best just to use Math/pow.
The other thing you could do is adjust your h value in volumeIntegral but to avoid stack issues, use recur (which gives you tail recursion), e.g. here's a slightly modified version:
(defn volume-integral [f a b]
(defn area[r]
(* Math/PI (* r r)))
(def h 0.000001)
(def n (/ (abs (- b a)) h))
((fn [i sum]
(if (not (< i n))
(* h (+ (/ (+ (f a) (f b)) 2) sum))
(recur (+ i 1) (+ sum (area (f (+ (* i h) a)))))))
0 0))
(I did the something similar with integral.) All in all, I wasn't able to quite hit the second figure, but this should get you on the right track:
101.33517384995224
41119.11576557253

Counting numbers or characters in list in Scheme

does anyone know how to count all numbers or characters in list and print it in pair in this format: (number . number_of_occurrences). For example:
(count '(3 1 3 2 1 2 3 3 3))
((3 . 5) (1 . 2) (2 . 2))
(count '(d b a c b b a))
((d . 1) (b . 3) (a . 2) (c . 1))
Thanks in advance for helping me :)
Here's an idea - use a hash table to keep track of the number of occurrences. This is an O(n) procedure:
(define (counter lst)
(let ((counts (make-hash)))
(let loop ((lst lst))
(cond ((null? lst)
(hash->list counts))
(else
(hash-update! counts (car lst) add1
(lambda () 0))
(loop (cdr lst)))))))
Alternatively, here's a simpler version (it doesn't use filter) of #mobyte's solution in Scheme - noticing that this is O(n^2) and hence less efficient than the hash table-based procedure:
(define (counter lst)
(map (lambda (e)
(cons e (count (curry equal? e) lst)))
(remove-duplicates lst)))
Either way, It works as expected:
(counter '(3 1 3 2 1 2 3 3 3))
=> '((3 . 5) (2 . 2) (1 . 2))
(counter '(d b a c b b a))
=> '((b . 3) (a . 2) (d . 1) (c . 1))
This is solution in clojure. But I hope it'll be helpful:
(defn counter [l]
(map (fn [e]
[e (count (filter #{e} l))])
(distinct l)))
(counter [3 1 3 2 1 2 3 3 3])
-> ([3 5] [1 2] [2 2])
(counter '(d b a c b b a))
-> ([d 1] [b 3] [a 2] [c 1])

IllegalArguementException in clojure when trying to cons and reduce

i'm getting the error IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:487) when executing the following code:
(defn phrase-length [phr]
(loop [n 0 b () s ()]
(if (= n (count phr))
(concat #(reduce + b) #(reduce + s))
(recur (inc n)
(cons (nth (nth (nth phr n) 1) 0) b)
(cons (nth (nth (nth phr n) 1) 1) s)))))
The error is occurring in the line of the concat. It must be something with trying to reduce while also concatting.
You're trying to concat #(reduce + b) and #(reduce + s). That doesn't work, #(reduce + b) expands to (fn* [] (clojure.core/reduce clojure.core/+ your-namespace/b)). You can't concat functions. Maybe you meant (reduce + b) but that doesn't make any sense either because the result of that is a number, and you can't concat numbers either. Maybe you meant
[(reduce + b) (reduce + s)] or (map + b s) or (+ (reduce + b) (reduce + s)) but I can't do more than blindly guess here without knowing what you're actually trying to achieve.
These lines:
(cons (nth (nth (nth phr n) 1) 0) b)
(cons (nth (nth (nth phr n) 1) 1) s)
are weird too. Is phr a seq of seqs of seqs of longs?
Is your collection of this form [[[0 0 ,,,] [0 1 ,,,] ,,,] ,,,] (you'd cons 0 to b and 1 to s here)? If so, you should probably write functions for accessing those values, as it is it's a chore to find out what's going on.
nth returns a value.
When you do (cons (nth (nth (nth phr n) 1) 0) b), after the evaluation of the (nth phr n) you will apply the next nth in a value, not in a Seq.
Testing your code with something like (phrase-length "123") will raise the error that you are getting.

Is there a ":until" like command in clojure?

I want to perform the following nested operations until the experession is satisfied..
Is there a :until keyword which stops doing further operations when the condition matches.?
This command generates the Pythagoran Triplet 3 4 5. I dont want it to do anything else once it gets to that sequence of numbers.
(for [a (range 1 100)
b (range 1 100)
c (list (Math/sqrt (+ (Math/pow (int a) 2) (Math/pow (int b) 2))))
:when (= 12 (+ a b c))]
(list a b c))
:while is a short-circuiting test in for expressions. List elements will be generated until the first time it encounters a failing test.
In your case
(for [<code omitted> :while (not (= 12 (+ a b c)))] (list a b c))
would stop generating elements as soon as it found the triplet summing to 12.
One problem though, it doesn't do what you're expecting. The triplet itself would not be part of the result since it failed the test.
A list comprehension may not be the best solution if you are only looking for a single matching result. Why not just use a loop?
(loop [xs (for [a (range 1 100)
b (range 1 100)] [a, b])]
(when (seq xs)
(let [[a, b] (first xs)
c (Math/sqrt (+ (Math/pow (int a) 2)
(Math/pow (int b) 2)))]
(if (not (= 12 (+ a b c)))
(recur (next xs))
(list a b c)))))
Since for yields a lazy sequence you will get the desired result by picking the first element:
(first (for [a (range 1 100)
b (range 1 100)
c (list (Math/sqrt (+ (Math/pow (int a) 2)
(Math/pow (int b) 2))))
:when (= 12 (+ a b c))]
(list a b c))
Only the first element of the generated list is computed due to laziness, which can be demonstrated with a side effect:
user=> (first
(for [a (range 1 100)
b (range 1 100)
c (list (Math/sqrt (+ (Math/pow (int a) 2)
(Math/pow (int b) 2))))
:when (= 12 (+ a b c))]
(do (println "working...")
(list a b c))))
working...
(3 4 5.0)
(for ...) comes with a :let modifier so there is no need to wrap c in a list:
(for [a (range 1 100)
b (range 1 100)
:let [c (Math/sqrt (+ (Math/pow (int a) 2)
(Math/pow (int b) 2)))]
:when (= 12 (+ a b c))]
(list a b c))