Given a vector, or possibly nested vector, how do you iterate a function in Clojure over the vector (nested vector) n times? Moreover, how can you output each level of iteration into a vector? Whereby the output vector starts with the initial conditions, namely the input vector (nested vector), followed by the subsequent iterations.
I think what you want is iterate. It returns a lazy sequence of the iterations, starting with the input. So, for example:
(def init (range 10))
(take 3 (iterate #(map inc %) init))
;; gives ((0 1 2 3 4 5 6 7 8 9) (1 2 3 4 5 6 7 8 9 10) (2 3 4 5 6 7 8 9 10 11))
Related
So, I have a list of items. I want to replace each occurrence of an item based on a criteria with a set of elements in it's place.
Ideally, map can let you convert a list of N elements into another list of N elements but here the length will increase as we insert more elements at index where we had other individual elements replaced by a list of elements in place.
As proposed by #Lee you can do it using mapcat.
E.g:
(mapcat #(if (even? %) [% %] [%]) (range 10))
will result into:
=> (0 0 1 2 2 3 4 4 5 6 6 7 8 8 9)
Rather than map, you can use reduce, starting with an empty accumulator collection [].
(reduce #(conj %1 (dec %2) %2)
[]
[1 3 5 7])
So here, starting with a collection of odd numbers [1 3 5 7], we are adding extra even numbers into the sequence. Output is:
[0 1 2 3 4 5 6 7]
I have a simple sequence of arbitrary elements that I would like to reduce over two-by-two.
In order to do that, I generate pairs with the data, but the way I do it is wrong since I need to call a function generating the data twice :
(defn gen-pairs [l]
(partition 2 (drop 1 (take l (interleave (gen-data) (gen-data))))))
How can I avoid calling gen-data twice (gen-data returns a sequence of items lazily, like range for instance) ?
Your question would be clearer if you included an example of what output you wanted, but I think that you're after partition with a step of 1:
user=> (partition 2 1 [1 2 3 4 5 6 7])
((1 2) (2 3) (3 4) (4 5) (5 6) (6 7))
What I am ultimately trying to do is multiply two vectors together and return a vector of the same size eg:
[6 7 8 9 10] * [0 1 3 1 0] => [0 7 24 9 0]
I was attempting to do something like:
(partition 2 (interleave [6 7 8 9 10] [0 1 3 1 0])) => ((6 0) (7 1) (8 3) (9 1) (10 0))
... then multiply each nested list value and use flatten to get:
(0 7 24 9 0)
but I cant figure out how I could multiply nested list values?
Map takes multiple sequences and a function to combine each member with the corresponding member of the other sequences.
user> (map * [6 7 8 9 10] [0 1 3 1 0])
(0 7 24 9 0)
user> (mapv * [6 7 8 9 10] [0 1 3 1 0])
[0 7 24 9 0]
in this case it calls * on the first number from each list, then on the second from each list and so on, building a seq of the output. If you would prefer the output in a vector mapv is convenient.
How does one write a function to split a list and then merge it back together such that the resulting list represents the shuffle of a deck?
The list (1 2 3 4 5 6 7 8 9 10) should end up as (1 6 2 7 3 8 4 9 5 10)
Is there a way to use split-at or reduce or some other function to achieve this?
So far I'm here:
(defn shuffle [cards]
(split-at (/ (count cards) 2) cards)
)
(apply interleave (split-at 5 (range 1 11)))
(1 6 2 7 3 8 4 9 5 10)
Clojure has an excellent selection of sequence functions.
user> (range 1 11)
(1 2 3 4 5 6 7 8 9 10)
user> (apply mapcat list (split-at 5 (range 1 11)))
(1 6 2 7 3 8 4 9 5 10)
You can get an overview at the clojure cheatsheet, it's a little out of date but mostly still relevant, and gives a good overview of the Clojure basics.
Split like you already have, then zip the two halves together and flatten:
(defn shuffle [cards]
(->> cards
(split-at (/ (count cards) 2))
(apply map list)
(flatten)))
(shuffle '(1 2 3 4 5 6 7 8 9 10)) ;=> (1 6 2 7 3 8 4 9 5 10)
Of course if you want a “truly” random shuffle, use clojure.core/shuffle.
A general solution is
(defn riffle [s]
(let [v (vec s), c (quot (count v) 2)]
(interleave (subvec v 0 c) (subvec v c))))
In this case
(riffle '(1 2 3 4 5 6 7 8 9 10))
; (1 6 2 7 3 8 4 9 5 10)
I have been playing around with clojure, and decided to make a higher order function that combines mapcat and list to emulate this behavior:
Clojure> (mapcat list '(1 2 3 4) '(5 6 7 8))
(1 5 2 6 3 7 4 8)
my first attempt was defining mapcatList as follows:
Clojure> (defn mapcatList[& more](mapcat list more))
#'sandbox99/mapcatList
Clojure> (mapcatList '(1 2 3 4) '(5 6 7 8))
((1 2 3 4) (5 6 7 8))
Obviously the function does not behave how I would like it, and I think this is because the two lists are being put into one list and passed as a single argument, not two.
I was able to remedy the situation with the following,
Clojure> (defn mapcatList[x y & more](mapcat list x y))
#'sandbox99/mapcatList
Clojure> (mapcatList '(1 2 3 4) '(5 6 7 8))
(1 5 2 6 3 7 4 8)
This solution works well with two lists, but I would like the function to work with a variable number of arguments.
My question: How can I pass a variable number of argument to a function, then destructure them so they are passed as individual arguments together to 'mapcat list'?
You are looking for apply. This calls a function with the arguments supplied in a sequence.
But are you aware that there's a function interleave that does exactly what your mapcatList tries to do?
You're right, the arguments are wrapped in a list as a result of the vararg declaration. You need to apply the arguments in order to unwrap the list of arguments:
(defn mapcatList[& more]
(apply mapcat list more))
user=> (mapcatList '(1 2 3 4) '(5 6 7 8))
(1 5 2 6 3 7 4 8)
user=> (mapcatList '(1 2 3 4) '(5 6 7 8) '(\a \b \c \d))
(1 5 \a 2 6 \b 3 7 \c 4 8 \d)