Building tables in clojure - clojure

If I wanted to build a table in Clojure of vector duplicates, I'd write:
(take 2 (repeat [1 2 3]))
But how would I expand this notion of a table function to build something like:
Input 1: [a^2 2 6 2] where a^2 is some input function, 2 is min value, 6 is max value, and 2 is step size.
Output 1: [4,16,36]
Input 2: [b^2 10 -5 -2]
Output 2: [100 64 36 16 4 0 4 16]
This outputs a 4x3 matrix
Input 3: [(+ (* 10 i) j) [1 4] [1 3]]
where (+ (* 10 i) j) is 10i+j (some given input function), [1 4] is the min and max of i, and [1 3] is the min and max of j.
Output 3: [[11 12 13] [21 22 23] [31 32 33] [41 42 43]]

You want to use for in a nested fashion:
(for [i (range 1 (inc 4))]
(for [j (range 1 (inc 3))]
(+ (* 10 i) j)))
;; '((11 12 13) (21 22 23) (31 32 33) (41 42 43))
EDIT: expanded with an example implementation
For example:
(defn build-seq [f lower upper step]
(for [i (range lower (+ upper step) step)]
(f i)))
(build-seq #(* % %) 2 6 2)
;; '(4 16 36)
(defn build-table [f [ilower iupper] [jlower jupper]]
(for [i (range ilower (inc iupper))]
(for [j (range jlower (inc jupper))]
(f i j))))
(build-table #(+ (* 10 %) %2) [1 4] [1 3])
;; '((11 12 13) (21 22 23) (31 32 33) (41 42 43))
Your three input/output samples do not display a consistent signature for one variable and two ; furthermore, the step argument seems to be optional. I'm skeptical about the existence of a nice API that would retain the samples' syntax, but I can try something different (even if I do believe the simple embedded for forms are a better solution):
(defn flexible-range [{:keys [lower upper step] :or {lower 0}}]
(let [[upper step] (cond
(and upper step) [(+ upper step) step]
step (if (pos? step)
[Double/POSITIVE_INFINITY step]
[Double/NEGATIVE-INFINITY step])
upper (if (< lower upper)
[(inc upper) 1]
[(dec upper) -1])
:else [Double/POSITIVE_INFINITY 1])]
(range lower upper step)))
(defn build-table
([f [& params]]
(for [i (flexible-range params)]
(f i)))
([f [& iparams] [& jparams]]
(for [i (flexible-range iparams)]
(for [j (flexible-range jparams)]
(f i j)))))
(build-table #(* % %) [:lower 2 :upper 6 :step 2])
;; '(4 16 36)
(build-table #(+ (* 10 %) %2) [:lower 1 :upper 4]
[:lower 1 :upper 3])
;; '((11 12 13) (21 22 23) (31 32 33) (41 42 43))

I think you can easily solve it with map and range
(defn applier
[f ini max step]
(map f (range ini (+ max step) step)))
(applier #(* % %) 2 6 2)
=> (4 16 36)

This fn can resolve your third example
(defn your-fn [[ra1 ra2] [rb1 rb2] the-fn]
(vec (map (fn [i] (vec (map (fn [j] (the-fn i j)) (range rb1 (inc rb2))))) (range ra1 (inc ra2))))
)
(your-fn [1 4] [1 3] (fn [i j] (+ (* 10 i) j)))
=> [[11 12 13] [21 22 23] [31 32 33] [41 42 43]]
But i'd need a few more specification details (or more use cases) to make this behavior generic, maybe you can explain a little more your problem. I think the 1st-2nd and the 3rd examples don't take the same type of parameters and meaning, (step vs seq ). So the #Guillermo-Winkler solves part the problem and my-fn will cover the last example

Related

clojure split collection in chunks of increasing size

Hi I am a clojure newbie,
I am trying to create a function that splits a collection into chunks of increasing size something along the lines of
(apply #(#(take %) (range 1 n)) col)
where n is the number of chunks
example of expected output:
with n = 4 and col = (range 1 4)
(1) (2 3) (4)
with n = 7 and col = (range 1 7)
(1) (2 3) (4 5 6) (7)
You can use something like this:
(defn partition-inc
"Partition xs at increasing steps of n"
[n xs]
(lazy-seq
(when (seq xs)
(cons (take n xs)
(partition-inc (inc n) (drop n xs))))))
; (println (take 5 (partition-inc 1 (range))))
; → ((0) (1 2) (3 4 5) (6 7 8 9) (10 11 12 13 14))
Or if you want to have more influence, you could alternatively provide
a sequence for the sizes (behaves the same as above, if passed (iterate inc 1) for sizes:
(defn partition-sizes
"Partition xs into chunks given by sizes"
[sizes xs]
(lazy-seq
(when (and (seq sizes) (seq xs))
(let [n (first sizes)]
(cons (take n xs) (partition-sizes (rest sizes) (drop n xs)))))))
; (println (take 5 (partition-sizes (range 1 10 2) (range))))
; → ((0) (1 2 3) (4 5 6 7 8) (9 10 11 12 13 14 15) (16 17 18 19 20 21 22 23 24))
An eager solution would look like
(defn partition-inc [coll]
(loop [rt [], c (seq coll), n 1]
(if (seq c)
(recur (conj rt (take n c)) (drop n c) (inc n))
rt)))
another way would be to employ some clojure sequences functions:
(->> (reductions (fn [[_ x] n] (split-at n x))
[[] (range 1 8)]
(iterate inc 1))
(map first)
rest
(take-while seq))
;;=> ((1) (2 3) (4 5 6) (7))
Yet another approach...
(defn growing-chunks [src]
(->> (range)
(reductions #(drop %2 %1) src)
(take-while seq)
(map-indexed take)
rest))
(growing-chunks [:a :b :c :d :e :f :g :h :i])
;; => ((:a) (:b :c) (:d :e :f) (:g :h :i))

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))

clojure: partition a seq based on a seq of values

I would like to partition a seq, based on a seq of values
(partition-by-seq [3 5] [1 2 3 4 5 6])
((1 2 3)(4 5)(6))
The first input is a seq of split points.
The second input is a seq i would like to partition.
So, that the first list will be partitioned at the value 3 (1 2 3) and the second partition will be (4 5) where 5 is the next split point.
another example:
(partition-by-seq [3] [2 3 4 5])
result: ((2 3)(4 5))
(partition-by-seq [2 5] [2 3 5 6])
result: ((2)(3 5)(6))
given: the first seq (split points) is always a subset of the second input seq.
I came up with this solution which is lazy and quite (IMO) straightforward.
(defn part-seq [splitters coll]
(lazy-seq
(when-let [s (seq coll)]
(if-let [split-point (first splitters)]
; build seq until first splitter
(let [run (cons (first s) (take-while #(<= % split-point) (next s)))]
; build the lazy seq of partitions recursively
(cons run
(part-seq (rest splitters) (drop (count run) s))))
; just return one partition if there is no splitter
(list coll)))))
If the split points are all in the sequence:
(part-seq [3 5 8] [0 1 2 3 4 5 6 7 8 9])
;;=> ((0 1 2 3) (4 5) (6 7 8) (9))
If some split points are not in the sequence
(part-seq [3 5 8] [0 1 2 4 5 6 8 9])
;;=> ((0 1 2) (4 5) (6 8) (9))
Example with some infinite sequences for the splitters and the sequence to split.
(take 5 (part-seq (iterate (partial + 3) 5) (range)))
;;=> ((0 1 2 3 4 5) (6 7 8) (9 10 11) (12 13 14) (15 16 17))
the sequence to be partitioned is a splittee and the elements of split-points (aka. splitter) marks the last element of a partition.
from your example:
splittee: [1 2 3 4 5 6]
splitter: [3 5]
result: ((1 2 3)(4 5)(6))
Because the resulting partitions is always a increasing integer sequence and increasing integer sequence of x can be defined as start <= x < end, the splitter elements can be transformed into end of a sequence according to the definition.
so, from [3 5], we want to find subsequences ended with 4 and 6.
then by adding the start, the splitter can be transformed into sequences of [start end]. The start and end of the splittee is also used.
so, the splitter [3 5] then becomes:
[[1 4] [4 6] [6 7]]
splitter transformation could be done like this
(->> (concat [(first splittee)]
(mapcat (juxt inc inc) splitter)
[(inc (last splittee))])
(partition 2)
there is a nice symmetry between transformed splitter and the desired result.
[[1 4] [4 6] [6 7]]
((1 2 3) (4 5) (6))
then the problem becomes how to extract subsequences inside splittee that is ranged by [start end] inside transformed splitter
clojure has subseq function that can be used to find a subsequence inside ordered sequence by start and end criteria. I can just map the subseq of splittee for each elements of transformed-splitter
(map (fn [[x y]]
(subseq (apply sorted-set splittee) <= x < y))
transformed-splitter)
by combining the steps above, my answer is:
(defn partition-by-seq
[splitter splittee]
(->> (concat [(first splittee)]
(mapcat (juxt inc inc) splitter)
[(inc (last splittee))])
(partition 2)
(map (fn [[x y]]
(subseq (apply sorted-set splittee) <= x < y)))))
This is the solution i came up with.
(def a [1 2 3 4 5 6])
(def p [2 4 5])
(defn partition-by-seq [s input]
(loop [i 0
t input
v (transient [])]
(if (< i (count s))
(let [x (split-with #(<= % (nth s i)) t)]
(recur (inc i) (first (rest x)) (conj! v (first x))))
(do
(conj! v t)
(filter #(not= (count %) 0) (persistent! v))))))
(partition-by-seq p a)

Neat way to apply a function to every nth element of a sequence?

What's a neat way to map a function to every nth element in a sequence ? Something like (map-every-nth fn coll n), so that it would return the original sequence with only every nth element transformed, e.g. (map-every-nth inc (range 16) 4) would return (0 1 2 4 4 5 6 8 8 9 10 12 12 13 14 16)
Try this:
(defn map-every-nth [f coll n]
(map-indexed #(if (zero? (mod (inc %1) n)) (f %2) %2) coll))
(map-every-nth inc (range 16) 4)
> (0 1 2 4 4 5 6 8 8 9 10 12 12 13 14 16)
I suggest that this would be simpler and cleaner than the accepted answer:
(defn map-every-nth [f coll n]
(map f (take-nth n coll)))
This is a handy one to know: http://clojuredocs.org/clojure_core/clojure.core/take-nth
I personally like this solution better:
(defn apply-to-last [f col] (concat (butlast col) (list (f (last col)))))
(apply concat (map #(apply-to-last (fn [x] (* 2 x)) %) (partition 4 (range 16))))
Or as a function:
(defn apply-to-last [f col] (concat (butlast col) (list (f (last col)))))
(defn map-every-nth [f col n] (apply concat (map #(apply-to-last f %) (partition n col))))
(map-every-nth (fn [x] (* 2 (inc x))) (range 16) 4)
; output: (0 1 2 8 4 5 6 16 8 9 10 24 12 13 14 32)
Notice this easily leads to the ability to apply-to-first, apply-to-second or apply-to-third giving the ability to control the "start" of mapping every nth element.
I do not know the performance of the code I wrote above, but it does seem more idiomatic to me.

Changing map behaviour in Clojure

I need to modify map function behavior to provide mapping not with minimum collection size but with maximum and use zero for missing elements.
Standard behavior:
(map + [1 2 3] [4 5 6 7 8]) => [5 7 9]
Needed behavior:
(map + [1 2 3] [4 5 6 7 8]) => [5 7 9 7 8]
I wrote function to do this, but it seems not very extensible with varargs.
(defn map-ext [f coll1 coll2]
(let [mx (max (count coll1) (count coll2))]
(map f
(concat coll1 (repeat (- mx (count coll1)) 0))
(concat coll2 (repeat (- mx (count coll2)) 0)))))
Is there a better way to do this?
Your method is concise, but inefficient (it calls count). A more efficient solution, which does not require the entirety of its input sequences to be stored in memory follows:
(defn map-pad [f pad & colls]
(lazy-seq
(let [seqs (map seq colls)]
(when (some identity seqs)
(cons (apply f (map #(or (first %) pad) seqs))
(apply map-pad f pad (map rest seqs)))))))
Used like this:
user=> (map-pad + 0 [] [1] [1 1] (range 1 10))
(3 3 3 4 5 6 7 8 9)
Edit: Generalized map-pad to arbitrary arity.
Another lazy variant, usable with an arbitrary number of input sequences:
(defn map-ext [f ext & seqs]
(lazy-seq
(if (some seq seqs)
(cons (apply f (map #(if (seq %) (first %) ext) seqs))
(apply map-ext f ext (map rest seqs)))
())))
Usage:
user> (map-ext + 0 [1 2 3] [4 5 6 7 8])
(5 7 9 7 8)
user> (map-ext + 0 [1 2 3] [4 5 6 7 8] [3 4])
(8 11 9 7 8)
If you just want it to work for any number of collections, try:
(defn map-ext [f & colls]
(let [mx (apply max (map count colls))]
(apply map f (map #(concat % (repeat (- mx (count %)) 0)) colls))))
Clojure> (map-ext + [1 2] [1 2 3] [1 2 3 4])
(3 6 6 4)
I suspect there may be better solutions though (as Trevor Caira suggests, this solution isn't lazy due to the calls to count).
How about that:
(defn map-ext [f x & xs]
(let [colls (cons x xs)
res (apply map f colls)
next (filter not-empty (map #(drop (count res) %) colls))]
(if (empty? next) res
(lazy-seq (concat res (apply map-ext f next))))))
user> (map-ext + [1 2 3] [4] [5 6] [7 8 9 10])
(17 16 12 10)
Along the lines of #LeNsTR's solution, but simpler and faster:
(defn map-ext [f & colls]
(lazy-seq
(let [colls (filter seq colls)
firsts (map first colls)
rests (map rest colls)]
(when (seq colls)
(cons (apply f firsts) (apply map-ext f rests))))))
(map-ext + [1 2 3] [4] [5 6] [7 8 9 10])
;(17 16 12 10)
I've just noticed Michał Marczyk's accepted solution, which is superior: it deals properly with asymmetric mapping functions such as -.
We can make Michał Marczyk's answer neater by using the convention - which many core functions follow - that you get a default or identity value by calling the function with no arguments. For examples:
(+) ;=> 0
(concat) ;=> ()
The code becomes
(defn map-ext [f & seqs]
(lazy-seq
(when (some seq seqs)
(cons (apply f (map #(if (seq %) (first %) (f)) seqs))
(apply map-ext f (map rest seqs)))
)))
(map-ext + [1 2 3] [4 5 6 7 8] [3 4])
;(8 11 9 7 8)
I've made the minimum changes. It could be speeded up a bit.
We may need a function that will inject such a default value into a function that lacks it:
(defn with-default [f default]
(fn
([] default)
([& args] (apply f args))))
((with-default + 6)) ;=> 6
((with-default + 6) 7 8) ;=> 15
This could be speeded up or even turned into a macro.