In this question, you are given a value V and a list of unique integers. Your job is to find the number of distinct subsets of size 4 that sum up to V. Each element in the list can be used only once. If none of such subset can be found, output 0 instead.
For example, if the integers are [3, 4, 5, 6, 7, 8, 9, 10] and the value is 30, the output should be 5. The subsets are:
[3, 8, 9, 10]
[4, 7, 9, 10]
[5, 6, 9, 10]
[5, 7, 8, 10]
[6, 7, 8, 9].
It is not hard to solve this question, the most direct way is to nest for-loop four times. What's the Clojure way to do it?
Here is how I would've done it:
(ns example.solve
(:require [clojure.math.combinatorics :as combo]))
(defn solve
[s n v]
(filter (comp (partial = v)
(partial reduce +))
(combo/combinations s n)))
I'm using math.combinatorics in my example, because it's a simplest way to get all combinations of 4 elements from a list.
Here is an example of using solve:
=> (solve [3 4 5 6 7 8 9 10] 4 30)
((3 8 9 10) (4 7 9 10) (5 6 9 10) (5 7 8 10) (6 7 8 9))
I would use clojure.map.combinatorics/combinations to get all 4-element subsets and then filter out those that do not sum up to V.
Interestingly, this problem admits a (doubly?) recursive solution which involves only summing and counting (without actually generating the subsets.)
If you look at the initial element 3, then part of the solution is the number of sums taken from 3 elements in the rest of the sequence where the sum is 27, which is a smaller form of the same problem and can thus be solved recursively. The bottom of the recursion is when you are looking for sums produced from 1 element, which boils down to a simple check to see if the desired sum is in the list.
The other part of the solution involves looking at the next element 4, looking for sums in the rest of the list beyond the 4 equal to 26, and so on... This part can also be treated recursively.
Putting this together as a recursive function looks like the following, which produces the desired answer 5 for the example sequence.
(defn solve [xs n len]
(if (seq xs)
(if (= len 1)
(if (some #{n} xs) 1 0)
(+ (solve (rest xs)
(- n (first xs))
(dec len))
(solve (rest xs)
n
len)))
0))
(solve [3 4 5 6 7 8 9 10] 30 4)
;=> 5
In terms of directly answering the question, here is how you could do it using indexes and a for loop:
(defn solve-for [xs v]
(for [ndx0 (range 0 (- (count xs) 3))
ndx1 (range (inc ndx0) (- (count xs) 2))
ndx2 (range (inc ndx1) (- (count xs) 1))
ndx3 (range (inc ndx2) (count xs))
:when (= v (+ (xs ndx0) (xs ndx1) (xs ndx2) (xs ndx3)))]
(list (xs ndx0) (xs ndx1) (xs ndx2) (xs ndx3))))
FWIW, this turns out to be about 70% faster than the approach using clojure.math.combinatorics but twice as slow as the doubly-recursive solution.
Related
I'm trying to iterate over a list with a given step in clojure.
In python I would have done the following :
xs = list(range(10))
xs[::2]
# out: [0, 2, 4, 6, 8]
xs[1::2]
# out: [1, 3, 5, 7, 9]
I can't figure out a clojure solution that feels idiomatic.
Here is the best I can think of:
(defn iterate-step-2 [xs]
(map first (take-while some? (iterate nnext xs))))
(iterate-step-2 (range 10))
; out: (0 2 4 6 8)
(iterate-step-2 (rest (range 10)))
; out: (1 3 5 7 9)
But it's not as generic (step is not configurable) and as flexible as the python solution. Plus it seems overly complicated.
Is there a better way to do this ?
You can use take-nth for this:
user=> (take-nth 2 (range 10))
(0 2 4 6 8)
user=> (take-nth 2 (rest (range 10)))
(1 3 5 7 9)
;; equivalent to Python's your_seq[1:7:2] would be:
(->> your-seq (drop 1) (take 7) (take-nth 2))
;; equivalent to Python's your_seq[::2] would be:
(->> your-seq (take-nth 2))
;; equivalent to Python's your_seq[2:4:-3] would be:
(->> your-seq (take 4) (drop 2) (reverse) (take-nth 3))
;; equivalent to Python's your_seq[2:-4:-1]:
(->> your-seq (take (+ 1 (- (length your-seq) 4))) (drop 2) (reverse))
Another option is to generate the desired index values, and then use those for the lookup:
(let [N 10
data (vec (range N)) ; `vec` is optional but faster than using (lazy) list if large N
idxs (range 1 10 2)
result (mapv #(nth data %) idxs)]
)
with result:
N => 10
data => [0 1 2 3 4 5 6 7 8 9]
idxs => (1 3 5 7 9)
result => [1 3 5 7 9]
or something less simple:
(let [N 9999
data (vec (range N)) ; `vec` is optional but faster than using (lazy) list if large N
idxs (mapv #(Math/pow 2 %) (range 11))
result (mapv #(nth data %) idxs)]
with result:
idxs => [1.0 2.0 4.0 8.0 16.0 32.0 64.0 128.0 256.0 512.0 1024.0]
result => [1 2 4 8 16 32 64 128 256 512 1024]
Interesting! Apparently nth will accept a floating-point index value as long as it has a zero fraction. :)
I am trying to find a method to implement Partition (with [] padding) in clojure. I think it's doable using loop and recur and mapping it into the list:
(defn collect-h [v n]
(loop [i n
res []
lst v
]
(if (= 0 i)
res
(recur (dec i) (cons (first lst) res) (next lst))
)
)
)
So the problem is that implementation only works on the first series of answer "(collect-h [1 2 3 4 5 6 7 8 9 10] 3) will give ((1 2 3))". So I need to map it to the whole collection and remove the first n number in every loop, but that doesn't look really efficient. I wonder if there is a better way to solve it.
Edit:
so it should work like this:
(collect-h [1 2 3 4 5 6 7 8 9 10] 3) ;; ((1 2 3) (4 5 6) (7 8 9) (10))
which is same to
(partition 3 3 [] [1 2 3 4 5 6 7 8 9 10])
#Timothy-Pratley answer is nice, but it is not tail recursive, meaning that it would cause stack overflow in case of large collection. Here is non stack consuming variant:
(defn my-partition [n items]
(loop [res [] items items]
(if (empty? items)
res
(recur (conj res (take n items))
(drop n items)))))
user> (my-partition 3 (range 10))
[(0 1 2) (3 4 5) (6 7 8) (9)]
Building off #Timothy-Pratley and the Clojure source code, you could also use lazy-seq:
(defn partition-ghetto [n xs]
(lazy-seq (when-let [s (seq xs)]
(cons (take n s) (partition-ghetto n (drop n s))))))
How about this?
(defn partition-ghetto [n xs]
(if (seq xs)
(cons (take n xs) (partition-ghetto n (drop n xs)))
()))
(partition-ghetto 3 (range 10))
=> ((0 1 2) (3 4 5) (6 7 8) (9))
Definitely not as good as the core version, but might provide some ideas?
Note that this recursive definition is not tail recursive, so will blow the stack for large sequences, nor is it lazy like most Clojure sequence functions. The advantage of laziness on sequences is that you are neither stack nor heap bound when operating on a stream. See alternative answers below that provide solutions to these concerns.
I tried to find a list of perfect number in this way:
(defn classify [num]
(let [factors (->> (range 1 (inc num))
(filter #(zero? (rem num %))))
sum (reduce + factors)
aliquot-sum (- sum num)]
(cond
(= aliquot-sum num) :perfect
(> aliquot-sum num) :abundant
(< aliquot-sum num) :deficient)))
(defn is-p [n]
(= :perfect (classify n)))
(defn list-perfect [n]
(filter is-p (range 1 (inc n))))
Question:
How to build a lazy sequence of perfect numbers, so that I can use (take n ...) to easily get a list.
Is this code idiomatic and efficient? Any improvement?
Thanks in advance.
Your algorithm is very inefficient, it's O(n).
For a quick win, you can immediately reduce the range by a half, as you won't ever have factors that are greater than the number you're testing divided by 2.
So change it to:
(defn classify [num]
(let [factors (->> (range 1 (max 2 (inc (quot num 2))))
;; ...
However... you can change it to O(sqrt n) which is magnitudes faster. See my timings below.
The real efficiency is noticing that factors are in pairs of [x (quot num x)] and then only check the first (sqrt num) (or slightly over):
(defn perfect? [n]
(let [r (range 2 (+ 2 (int (Math/sqrt n))))
s (set (mapcat #(if (zero? (rem n %))
[% (quot n %)])
r))
t (reduce + 1 s)]
(= n t)))
I've split it into separate calculations so you can verify each stage.
The range can be reduced from 2..((sqrt n) + 2), and initialise the reduction with 1 (which is always a factor).
This changes the problem from an O(n) to O(sqrt n), so if you're checking large numbers, makes a vast difference.
As an illustration here are some times on larger values for n on my MBP:
n "n/2" "sqrt n"
33550336 1,172.5ms 2.85ms
8589869056 274,346.6ms 16.76ms
137438691328 didn't time 44.27ms
so using root version was 16,369 times faster for the 6th perfect number. See http://en.wikipedia.org/wiki/List_of_perfect_numbers for more details.
EDIT:
Why (int (root n)) + 2? And why `[x (quot n x)]?
When you work out the factors of a number n, then if you find one (say, a), then n/a is also a factor (call it b) because n = a * b
e.g. looking at 28, the first relevant factor is 2, and clearly 28/2 = 14 is also a factor. So you don't need to check 14, you already know it's a factor from the fact that 2 is.
as we're incrementally checking numbers from 2 upwards, we're incidentally finding the higher numbers coming down:
2 is a factor, 28 / 2 = 14 -> [a, b] = [2, 14]
4 is a factor, 28 / 4 = 7 -> [a, b] = [4, 7]
7 is a factor, 28 / 7 = 4 -> [a, b] = [7, 4] - wait a minute...
The [a,b] pairs here are the [% (quot n %)] in the mapcat function, e.g. when the range is currently iterating the value 2, then % is 2 inside the fuction, and so (quot n %) is (quot 28 2) which is 14, thus [% (quot n %)] is simply the vector [2 14], which then gets added to the set after being flattened to 2 and 14 as values. Later, when the range value is 4, then [% (quot n %)] is [4 (quot 28 4)] which is [4 7], and again is flattened by mapcat as the numbers 4 and 7.
So we add each pair of numbers (flattened via mapcat) to our set, include the number 1, and end up with #{1 2 14 4 7}, which are the factors of 28. (Actually, I don't put 1 in the set as I don't need to, instead I start the summing reduction at 1, which is same effect).
But at what point do they turn around? i.e. when do we know that [7,4] will already have been included in the set as [4,7]?
clearly it's when a > b, because in finding the lowest numbers we always find the highest number with it, so we can finish checking at this point.
but what is this point? it's simple, if a perfect number were a square number, then a and b would be equal, i.e. a*a = n, so a = sqrt(n).
Thus the highest value of a we need to check is the whole number that is larger than the root of n.
e.g. for 28, sqrt(28) = 5.292, so we have to check 6 to be sure that we've included the lowest number possible that could be a factor that has a paired factor.
so we need (int (sqrt n)) + 1.
I always do this in case the root calculation is 1.9999999999... and rounds wrong way, so adding 1 more ensures you eliminate any rounding errors.
but in a range, if you want to include that number you have to add 1 more to it (range drops the high number, (range 6) = (0 1 2 3 4 5)), hence why it adds 2 to the value: 1 for the range, 1 to ensure it's above the rounded down root.
Although, after saying this, I've tested perfect numbers up to 2305843008139952128 and it works with +1 instead of +2, not that it's a massive saving. Probably because non of the perfect numbers are close to perfect squares in ones I checked, so there's no rounding error in (int (sqrt n)).
If you're interested in perfect numbers, I'd recommend reading http://britton.disted.camosun.bc.ca/perfect_number/lesson1.html
list-perfect is already lazy due to your usage of filter:
(filter pred coll)
Returns a lazy sequence of the items in coll for which
(pred item) returns true. pred must be free of side-effects.
Whether code is idiomatic or not might be a matter of opinion (and hence off-topic), but it looks good enough from my perspective.
I wrote this code to nest a function n times and am trying to extend the code to handle a test. Once the test returns nil the loop is stopped. The output be a vector containing elements that tested true. Is it simplest to add a while loop in this case? Here is a sample of what I've written:
(defn nester [a inter f]
(loop [level inter expr a]
(if (= level 0) expr
(if (> level 0) (recur (dec level) (f expr))))))
An example input would be an integer 2, and I want to nest the inc function until the output is great than 6. The output should be [2 3 4 5 6 7].
(defn nester [a inter f test-fn]
(loop [level inter
expr a]
(if (or (zero? level)
(nil? (test-fn expr)))
expr
(recur (dec level)
(f expr)))))
If you also accept false (additionally to nil) from your test-fn, you could compose this more lazily:
(defn nester [a inter f test-fn]
(->> (iterate f a)
(take (inc inter))
(drop-while test-fn)
first))
EDIT: The above was answered to your initial question. Now that you have specified completely changed the meaning of your question:
If you want to generate a vector of all iterations of a function f over a value n with a predicate p:
(defn nester [f n p]
(->> (iterate f n)
(take-while p)
vec))
(nester inc 2 (partial > 8)) ;; predicate "until the output is greater than six"
;; translated to "as long as 8 is greater than
;; the output"
=> [2 3 4 5 6 7]
To "nest" or iterate a function over a value, Clojure has the iterate function. For example, (iterate inc 2) can be thought of as an infinite lazy list [2, (inc 2), (inc (inc 2)), (inc (inc (inc 2))) ...] (I use the [] brackets not to denote a "list"--in fact, they represent a "vector" in Clojure terms--but to avoid confusion with () which can denote a data list or an s-expression that is supposed to be a function call--iterate does not return a vector). Of course, you probably don't want an infinite list, which is where the lazy part comes in. A lazy list will only give you what you ask it for. So if you ask for the first ten elements, that's what you get:
user> (take 10 (iterate inc 2))
> (2 3 4 5 6 7 8 9 10 11)
Of course, you could try to ask for the whole list, but be prepared to either restart your REPL, or dispatch in a separate thread, because this call will never end:
user> (iterate inc 2)
> (2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
=== Shutting down REPL ===
=== Starting new REPL at C:\Users\Omnomnomri\Clojure\user ===
Clojure 1.5.0
user>
Here, I'm using clooj, and this is what it looks like when I restart my REPL. Anyways, that's all just a tangent. The point is that iterate answers the core of your question. The other part, stopping upon some test condition, involves take-while. As you might imagine, take-while is a lot like take, only instead of stopping after some number of elements, it stops upon some test condition (or in Clojure parlance, a predicate):
user> (take-while #(< % 10) (iterate inc 2))
> (2 3 4 5 6 7 8 9)
Note that take-while is exclusive with its predicate test, so that here once the value fails the test (of being less than 10), it excludes that value, and only includes the previous values in the return result. At this point, solving your example is pretty straightfoward:
user> (take-while #(< % 7) (iterate inc 2))
> (2 3 4 5 6)
And if you need it to be a vector, wrap the whole thing in a call to vec:
user> (vec (take-while #(< % 7) (iterate inc 2)))
> [2 3 4 5 6]
In Scala, the partition method splits a sequence into two separate sequences -- those for which the predicate is true and those for which it is false:
scala> List(1, 5, 2, 4, 6, 3, 7, 9, 0, 8).partition(_ % 2 == 0)
res1: (List[Int], List[Int]) = (List(2, 4, 6, 0, 8),List(1, 5, 3, 7, 9))
Note that the Scala implementation only traverses the sequence once.
In Clojure the partition-by function splits the sequence into multiple sub-sequences, each the longest subset that either does or does not meet the predicate:
user=> (partition-by #(= 0 (rem % 2)) [1, 5, 2, 4, 6, 3, 7, 9, 0, 8])
((1 5) (2 4 6) (3 7 9) (0 8))
while the split-by produces:
user=> (split-with #(= 0 (rem % 2)) [1, 5, 2, 4, 6, 3, 7, 9, 0, 8])
[() (1 5 2 4 6 3 7 9 0 8)]
Is there a built-in Clojure function that does the same thing as the Scala partition method?
I believe the function you are looking for is clojure.core/group-by. It returns a map of keys to lists of items in the original sequence for which the grouping function returns that key. If you use a true/false producing predicate, you will get the split that you are looking for.
user=> (group-by even? [1, 5, 2, 4, 6, 3, 7, 9, 0, 8])
{false [1 5 3 7 9], true [2 4 6 0 8]}
If you take a look at the implementation, it fulfills your requirement that it only use one pass. Plus, it uses transients under the hood so it should be faster than the other solutions posted thus far. One caveat is that you should be sure of the keys that your grouping function is producing. If it produces nil instead of false, then your map will list failing items under the nil key. If your grouping function produces non-nil values instead of true, then you could have passing values listed under multiple keys. Not a big problem, just be aware that you need to use a true/false producing predicate for your grouping function.
The nice thing about group-by is that it is more general than just splitting a sequence into passing and failing items. You can easily use this function to group your sequence into as many categories as you need. Very useful and flexible. That is probably why group-by is in clojure.core instead of separate.
Part of clojure.contrib.seq-utils:
user> (use '[clojure.contrib.seq-utils :only [separate]])
nil
user> (separate even? [1, 5, 2, 4, 6, 3, 7, 9, 0, 8])
[(2 4 6 0 8) (1 5 3 7 9)]
Please note that the answers of Jürgen, Adrian and Mikera all traverse the input sequence twice.
(defn single-pass-separate
[pred coll]
(reduce (fn [[yes no] item]
(if (pred item)
[(conj yes item) no]
[yes (conj no item)]))
[[] []]
coll))
A single pass can only be eager. Lazy has to be two pass plus weakly holding onto the head.
Edit: lazy-single-pass-separate is possible but hard to understand. And in fact, I believe this is slower then a simple second pass. But I haven't checked that.
(defn lazy-single-pass-separate
[pred coll]
(let [coll (atom coll)
yes (atom clojure.lang.PersistentQueue/EMPTY)
no (atom clojure.lang.PersistentQueue/EMPTY)
fill-queue (fn [q]
(while (zero? (count #q))
(locking coll
(when (zero? (count #q))
(when-let [s (seq #coll)]
(let [fst (first s)]
(if (pred fst)
(swap! yes conj fst)
(swap! no conj fst))
(swap! coll rest)))))))
queue (fn queue [q]
(lazy-seq
(fill-queue q)
(when (pos? (count #q))
(let [item (peek #q)]
(swap! q pop)
(cons item (queue q))))))]
[(queue yes) (queue no)]))
This is as lazy as you can get:
user=> (let [[y n] (lazy-single-pass-separate even? (report-seq))] (def yes y) (def no n))
#'user/no
user=> (first yes)
">0<"
0
user=> (second no)
">1<"
">2<"
">3<"
3
user=> (second yes)
2
Looking at the above, I'd say "go eager" or "go two pass."
It's not hard to write something that does the trick:
(defn partition-2 [pred coll]
((juxt
(partial filter pred)
(partial filter (complement pred)))
coll))
(partition-2 even? (range 10))
=> [(0 2 4 6 8) (1 3 5 7 9)]
Maybe see https://github.com/amalloy/clojure-useful/blob/master/src/useful.clj#L50 - whether it traverses the sequence twice depends on what you mean by "traverse the sequence".
Edit: Now that I'm not on my phone, I guess it's silly to link instead of paste:
(defn separate
[pred coll]
(let [coll (map (fn [x]
[x (pred x)])
coll)]
(vec (map #(map first (% second coll))
[filter remove]))))