`for` as a function instead of a macro [duplicate] - clojure

This question already has answers here:
Cartesian product in clojure
(6 answers)
Closed 2 years ago.
I'd like to have a forall function that acts like for but takes a list of sequences as inputs.
(forall (fn [arr]
(prn arr))
(range 10)
(range 10)
(range 10))
=>
; [0 0 0]
; [0 0 1]
; [0 0 2]
; ....
; [9 9 9]
Is there a good way to write this?

I suppose you want to map over the cartesian product of the input sequences, right? If so, you can create a lazy sequence of the cartesian product using for example the clojure.math.combinatorics/cartesian-product function from the clojure.math.combinatorics library and then map over that.
(defn forall [f & seqs]
(map f (apply clojure.math.combinatorics/cartesian-product seqs)))
This is a function that works more or less like the for macro when there are multiple sequences. Here is an example of calling it, and the result that you would obtain:
(forall (fn [arr]
[:element arr])
(range 3)
(range 3)
(range 3))
;; => ([:element (0 0 0)] [:element (0 0 1)] [:element (0 0 2)] [:element (0 1 0)] [:element (0 1 1)] [:element (0 1 2)] [:element (0 2 0)] [:element (0 2 1)] [:element (0 2 2)] [:element (1 0 0)] [:element (1 0 1)] [:element (1 0 2)] [:element (1 1 0)] [:element (1 1 1)] [:element (1 1 2)] [:element (1 2 0)] [:element (1 2 1)] [:element (1 2 2)] [:element (2 0 0)] [:element (2 0 1)] [:element (2 0 2)] [:element (2 1 0)] [:element (2 1 1)] [:element (2 1 2)] [:element (2 2 0)] [:element (2 2 1)] [:element (2 2 2)])
Note that in your example code, you call the prn function which is side-effectful, whereas the for-macro produces a lazy sequence. Combining laziness with side-effects is often discouraged because the side-effect may not happen when you would expect it to happen unless you know how lazy sequences work.
If you don't want to pull in the clojure.math.combinatorics library, you can easily implement your own cartesian product function, e.g.
(defn cart2 [a b]
(for [x a
y b]
(conj x y)))
(defn my-cartesian-product [& arrs]
(reduce cart2 [[]] arrs))

Related

Mysterious Clojure function

I would like to write a clojure function that has the following behaviour :
(take 4 (floyd))
=> '((1) (2 3) (4 5 6) (7 8 9 10))
(take 3 (floyd))
=> '((1) (2 3) (4 5 6))
(take 1 (floyd))
=> '((1)))
I tried using partition and partition-all to validate these tests however i couldn't get the right solution. If you have any idea of how to do it, i would really appreciate a little help. I started using clojure a few weeks ago and still have some issues.
Thanks
Here's another option:
(defn floyd []
(map (fn [lo n] (range lo (+ lo n 1)))
(reductions + 1 (iterate inc 1))
(range)))
(take 5 (floyd))
;=> ((1) (2 3) (4 5 6) (7 8 9 10) (11 12 13 14 15))
This was arrived at based on the observation that you want a series of increasing ranges (the (range) argument to map is used to produce a sequence of increasingly longer ranges), each one starting from almost the triangular number sequence:
(take 5 (reductions + 0 (iterate inc 1)))
;=> (0 1 3 6 10)
If we start that sequence from 1 instead, we get the starting numbers in your desired sequence:
(take 5 (reductions + 1 (iterate inc 1)))
;=> (1 2 4 7 11)
If the + 1 inside the mapped function bothers you, you could do this instead:
(defn floyd []
(map (fn [lo n] (range lo (+ lo n)))
(reductions + 1 (iterate inc 1))
(iterate inc 1)))
it is not possible to solve it with partition / partition-all, since they split your sequence into predefined size chunks.
What you can do, is to employ recursive lazy function for that:
user> (defn floyd []
(letfn [(f [n rng]
(cons (take n rng)
(lazy-seq (f (inc n) (drop n rng)))))]
(f 1 (iterate inc 1))))
#'user/floyd
user> (take 1 (floyd))
;;=> ((1))
user> (take 2 (floyd))
;;=> ((1) (2 3))
user> (take 3 (floyd))
;;=> ((1) (2 3) (4 5 6))
user> (take 4 (floyd))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10))
another variant can use similar approach, but only track chunk-start/chunk-size:
user> (defn floyd []
(letfn [(f [n start]
(cons (range start (+ start n))
(lazy-seq (f (inc n) (+ start n)))))]
(f 1 1)))
another approach is to use clojure's collection operating functions:
user> (defn floyd-2 []
(->> [1 1]
(iterate (fn [[start n]]
[(+ n start) (inc n)]))
(map (fn [[start n]] (range start (+ start n))))))
#'user/floyd-2
user> (take 4 (floyd-2))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10))
user> (take 5 (floyd-2))
;;=> ((1) (2 3) (4 5 6) (7 8 9 10) (11 12 13 14 15))
user> (take 1 (floyd-2))
;;=> ((1))
How about this:
(defn floyd []
(map (fn[n]
(let [start (/ (* n (inc n)) 2)]
(range (inc start) (+ start n 2))))
(iterate inc 0)))
(take 4 (floyd))

Drop function in clojure

Given the following function, I could not understand what map function is receiving as second parameter.
(def tails
(fn [seq]
(map drop
(range (inc (count seq)))
(repeat (inc (count seq)) seq))))
Given that seq is (list 1 2 3)
The line:
(range (inc (count seq)))
Will produce ((1 2 3) (1 2 3) (1 2 3))
And the line:
(range (inc (count seq)))
Will produce (0 1 2 3)
So, what is receiving the map function as second parameter?
The second parameter is seq repeated as many times as its length + 1, so you can drop 0 to length elements from it.
For '(1 2 3), you get
(map drop '(0 1 2 3) (repeat 4 '( 1 2 3)))
which (when realized) will become the equivalent of
(list (drop 0 '(1 2 3)) (drop 1 '(1 2 3)) (drop 2 '(1 2 3)) (drop 3 '(1 2 3)))
which evaluates to
((1 2 3) (2 3) (3) ())

Function related to partition that includes all elements?

This behavior of Clojure's partition function is not what I need:
user=> (partition 3 (range 3))
((0 1 2))
user=> (partition 3 (range 4))
((0 1 2))
user=> (partition 3 (range 5))
((0 1 2))
user=> (partition 3 (range 6))
((0 1 2) (3 4 5))
I need the 'leftover' portions of the collection to be included, e.g.:
user=> (partition* 3 (range 4))
((0 1 2) (3))
user=> (partition* 3 (range 5))
((0 1 2) (3 4))
Is there a standard library function that does what I want?
You're looking for partition-all. Just replace it in your example:
user> (partition-all 3 (range 4))
((0 1 2) (3))
user> (partition-all 3 (range 5))
((0 1 2) (3 4))
There is a pad argument in the 4-arity version of partition:
user=> (partition 3 3 [] (range 4))
((0 1 2) (3))
user=> (partition 3 3 [] (range 5))
((0 1 2) (3 4))
The docstring:
user=> (doc partition)
-------------------------
clojure.core/partition
([n coll] [n step coll] [n step pad coll])
Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
do not overlap. If a pad collection is supplied, use its elements as
necessary to complete last partition upto n items. In case there are
not enough padding elements, return a partition with less than n items.

How to move first list item to the end?

For given list:
(1 2 3 4)
I'd like to get as output:
(2 3 4 1)
Code I came up with looks like this:
(flatten (cons (rest l) (list (first l))))
However my feeling is, that I overcomplicated this. Any other ideas?
You don't need to flatten a cons, just use concat.
Here is an example:
(let [fruit ["apple" "orange" "grapes" "bananas"]]
(concat (rest fruit) [(first fruit)])
Developing #stonemetal's hint, we can quickly and lazily rotate a vector thus:
(defn rotate [v n]
(let [cv (count v), n (mod n cv)]
(concat (subvec v n cv) (subvec v 0 n))))
It works in either direction:
(map #(rotate (vec (range 5)) %) (range -2 8))
;((3 4 0 1 2)
; (4 0 1 2 3)
; (0 1 2 3 4)
; (1 2 3 4 0)
; (2 3 4 0 1)
; (3 4 0 1 2)
; ...
; (2 3 4 0 1))
So to rotate the first in a sequence to the end:
(rotate (vec (range 1 5)) 1)
You can also use destructuring (either on the function arguments or in a let binding).
(let [[h & tail] '(1 2 3 4)]
(concat tail (list h))) ;=> (1 2 3 4)

Sliding window over seq

In Clojure, what would be the nicest way to have a sliding window over a (finite, not too large) seq? Should I just use drop and take and keep track of the current index or is there a nicer way I'm missing?
I think that partition with step 1 does it:
user=> (partition 3 1 [3 1 4 1 5 9])
((3 1 4) (1 4 1) (4 1 5) (1 5 9))
If you want to operate on the windows, it can also be convenient to do this with map:
user=> (def a [3 1 4 1 5 9])
user=> (map (partial apply +) (partition 3 1 a))
(8 6 10 15)
user=> (map + a (next a) (nnext a))
(8 6 10 15)
I didn't know partition could do this so I implemented it this way
(defn sliding-window [seq length]
(loop [result ()
remaining seq]
(let [chunk (take length remaining)]
(if (< (count chunk) length)
(reverse result)
(recur (cons chunk result) (rest remaining))))))