Writing a tuples function that permutes all possible n-tuples - clojure

I'm working towards a tuples function, which takes collections and a parameter n. The parameter designates the number of indices the generated vector should have. The function then permutes all possible n-tuples of the elements in the collection.
So far I've been trying to combine functions from tuples.core and math.combinatoris,
namely, tuples and permutations.
(defn Tuples [& args]
(combo/permutations (tuple args)))
Example)
input: (0,1) n=3
output: [[0,0,0] [0,0,1] [0,1,0] [1,0,0] [0,1,1] [1,1,0] [1,0,1] [1,1,1]]

What you are looking for is clojure.math.combinatorics/selections:
(require '[clojure.math.combinatorics :as c])
(c/selections [0 1] 3)
;=> ((0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1))

Related

How to perform a map using reduce

Hello I have a simple function like this:
(def state
(memoize
(fn state [t]
(if (<= t 0)
0
1))))
on which I am trying to call (reduce state (range 10)) which the intent of calling the function state on the range 0 1 2 3 4 5 ..., and receiving back 0 1 1 1 1 1 1 1 1 1.
That is not happening, thus I am obviously misunderstanding something, since I am getting:
clojure.lang.ArityException: Wrong number of args (2) passed to: state
The syntax for reduce is (reduce f coll) and my understanding was that it is as simple as doing (reduce + [1 2 3 4 5]).
Obviously one can do this easily enough with map I was just under the impression that reduce would work as well. With map, (map (fn [x] (state x)) (range 10)).
PS. this is just a test case, I genuinely do need memoization for the real thing.
Thanks
Obviously one can do this easily enough with map I was just under the impression that reduce would work as well.
Yes. Any map can also be a reduce. (Except reduce is not lazy, while map is).
The result of a reduce function is going to be the result that is returned in the end after N iterations of your function over your reduction range.
Your function returns a 0 or a 1, therefore, your reduce will ultimately return either a 0 or 1.
If you want to return a list, then your reduction function needs to return a list. Or, use a function other than reduce, such as map.
Also -- all reduction functions take 2 arguments, not 1. So your state function is not a valid function to pass to reduce. Though, it is a valid function to pass to map.
Incidentally, you can do this with reduce, you don't need map -- in fact, many functions can be expressed as reduce, including map, filter and others. But, you'd need to alter your reduction function to make it compatible.
The comments and other answers suggest you must use map, but here is a reduce that will do it:
(def state
(memoize
(fn state [r t]
(if (<= t 0)
(conj r 0)
(conj r 1)))))
(reduce state [] (range 10))
;;-> [0 1 1 1 1 1 1 1 1 1]
This is a great idiom when you have logic for the value of a particular item that depends on knowing about the other items. You do not have such logic here, so map is a better choice. But conceptually you can express many things in functional programming in terms of a fold which is what reduce is.
Here is an alternate method, keeping the original state function from the question, and therefore its memoization intact:
(def state
(memoize
(fn state [t]
(if (<= t 0)
0
1))))
(defn r-fn [r t]
(conj r (state t)))
(reduce r-fn [] (range 10))
;;-> [0 1 1 1 1 1 1 1 1 1]
This is more succinctly written as:
(reduce #(conj %1 (state %2)) [] (range 10))
well, that's because the reduce function should take exactly 2 parameters: accumulator and item from the coll, bur in case the accumulator is not provided during reduce call, the first step of reduction is applied to first 2 values from coll:
(reduce + '(1 2 3 4)) is really (+ (+ (+ 1 2) 3) 4)
but that's not what you need in your case:
user> (map state (range 10))
(0 1 1 1 1 1 1 1 1 1)
as you don't want to reduce a coll to a single value, but rather map each value to another

Clojure. Drop-every?

Does the Clojure library have a "drop-every" type function? Something that takes a lazy list and returns a list with every nth item dropped?
Can't quite work out how to make this.
cheers
Phil
(defn drop-every [n xs]
(lazy-seq
(if (seq xs)
(concat (take (dec n) xs)
(drop-every n (drop n xs))))))
Example:
(drop-every 2 [0 1 2 3 4 5])
;= (0 2 4)
(drop-every 3 [0 1 2 3 4 5 6 7 8])
;= (0 1 3 4 6 7)
As a side note, drop-nth would be a tempting name, as there is already a take-nth in clojure.core. However, take-nth always returns the first item and then every nth item after that, whereas the above version of drop-every drops every nth item beginning with the nth item of the original sequence. (A function dropping the first item and every nth item after the first would be straightforward to write in terms of the above.)
If the input list length is a multiple of n you can use the partition function:
(defn drop-every [n lst] (apply concat (map butlast (partition n lst))))
(take 5 (drop-every 3 (range)))
; (0 1 3 4 6)

find all subsets of an integer collection that sums to n

i'm trying to find a function that, given S a set of integer and I an integer, return all the subsets of S that sum to I
is there such a function somewhere in clojure-contrib or in another library ?
if no, could anyone please give me some hints to write it the clojure way?
Isn't this the subset sum problem, a classic NP-complete problem?
In which case, I'd just generate every possible distinct subset of S, and see which subsets sums to I.
I think it is the subset sum problem, as #MrBones suggests. Here's a brute force attempt using https://github.com/clojure/math.combinatorics (lein: [org.clojure/math.combinatorics "0.0.7"]):
(require '[clojure.math.combinatorics :as c])
(defn subset-sum [s n]
"Return all the subsets of s that sum to n."
(->> (c/subsets s)
(filter #(pos? (count %))) ; ignore empty set since (+) == 0
(filter #(= n (apply + %)))))
(def s #{1 2 45 -3 0 14 25 3 7 15})
(subset-sum s 13)
; ((1 -3 15) (2 -3 14) (0 1 -3 15) (0 2 -3 14) (1 2 3 7) (0 1 2 3 7))
(subset-sum s 0)
; ((0) (-3 3) (0 -3 3) (1 2 -3) (0 1 2 -3))
These "subsets" are just lists. Could convert back to sets, but I didn't bother.
You can generate the subsets of a set like this:
(defn subsets [s]
(if (seq s)
(let [f (first s), srs (subsets (disj s f))]
(concat srs (map #(conj % f) srs)))
(list #{})))
The idea is to choose an element from the set s: the first, f, will do. Then we recursively find the subsets of everything else, srs. srs comprises all the subsets without f. By adding f to each of them, we get all the subsets with f. And together, that's the lot. Finally, if we can't choose an element because there aren't any, the only subset is the empty one.
All that remains to do is to filter out from all the subsets the ones that sum to n. A function to test this is
(fn [s] (= n (reduce + s)))
It is not worth naming.
Putting this together, the function we want is
(defn subsets-summing-to [s n]
(filter
(fn [xs] (= n (reduce + xs)))
(subsets s)))
Notes
Since the answer is a sequence of sets, we can make it lazier by changing concat into lazy-cat. map is lazy anyway.
We may appear to be generating a lot of sets, but remember that they share storage: the space cost of keeping another set differing by a single element is (almost) constant.
The empty set sums to zero in Clojure arithmetic.

clojure for sequence comprehnsion adding two elements at a time

The comprehension:
(for [i (range 5])] i)
... yields: (0 1 2 3 4)
Is there an idiomatic way to get (0 0 1 1 2 4 3 9 4 16) (i.e. the numbers and their squares) using mostly the for comprehension?
The only way I've found so far is doing a:
(apply concat (for [i (range 5)] (list i (* i i))))
Actually, using only for is pretty simple if you consider applying each function (identity and square) for each value.
(for [i (range 5), ; for every value
f [identity #(* % %)]] ; for every function
(f i)) ; apply the function to the value
; => (0 0 1 1 2 4 3 9 4 16)
Since for loops x times, it will return a collection of x values. Multiple nested loops (unless limited by while or when) will give x * y * z * ... results. That is why external concatenation will always be necessary.
A similar correlation between input and output exists with map. However, if multiple collections are given in map, the number of values in the returned collection is the size of the smallest collection parameter.
=> (map (juxt identity #(* % %)) (range 5))
([0 0] [1 1] [2 4] [3 9] [4 16])
Concatenating the results of map is so common mapcat was created. Because of that, one might argue mapcat is a more idiomatic way over for loops.
=> (mapcat (juxt identity #(* % %)) (range 5))
(0 0 1 1 2 4 3 9 4 16)
Although this is just shorthand for apply concat (map, and a forcat function or macro could be created just as easily.
However, if an accumulation over a collection is needed, reduce is usually considered the most idiomatic.
=> (reduce (fn [acc i] (conj acc i (* i i))) [] (range 5))
[0 0 1 1 2 4 3 9 4 16]
Both the for and map options would mean traversing a collection twice, once for the range, and once for concatenating the resulting collection. The reduce option only traverses the range.
Care to share why "using mostly the for comprehension" is a requirement ?
I think you are doing it right.
A slightly compressed way maybe achieved using flatten
(flatten (for [i (range 5)] [ i (* i i) ] ))
But I would get rid of the for comprehension and just use interleave
(let [x (range 5)
y (map #(* % %) x)]
(interleave x y))
Disclaimer: I am just an amateur clojurist ;)

How to count the number of ones in a vector, given an upper limit

Given a vector of ones and zeros, I would like to count the number of entries with a value one. However, the vector may be very long and I only care to know if the vector has zero, one, or more entries with a value o f one.
Using the approach given here, I can count the number of ones in the vector.
(count (filter #{1} [1 0 1 0 0 1 1]))
Can I limit filter (or use some other approach) to avoid visiting any more than three elements of the vector, in this case?
Filter is lazy, so will only do as much work as required. Since you only care about having no 1's, one 1's or two or more ones, you only need to examine up to two elements of the filtered sequence of 1's, so just take 2 before you count:
user=> (count (take 2 (filter #{1} [1 0 1 0 0 1 1])))
2
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 0])))
0
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 1])))
1
user=> (def rare (repeatedly #(if (< (rand) 0.0001) 1 0)))
#'user/rare
user=> (take 10 rare)
(0 0 0 0 0 0 0 0 0 0)
user=> (count (take 2 (filter #{1} rare)))
2