clojure - combine to structures to get flatter result - clojure

I am trying to combine 2 structures:
(def acc [[1]])
and
(def pairs '((2 4)))
I want the following result:
'((1 2) (1 4))
I have tried the following:
(map-indexed
(fn [idx pair]
(map (fn [itm]
(concat (nth acc idx) (vector itm))) pair)) pairs)
But this gives:
(((1 2) (1 4)))
I could call first but this falls apart as bigger lists are attempted.
For example if I had
(def acc '((1 2) (1 4)))
and
(def pairs '((5 1) (1 4)))
I want to the result to be:
'((1 2 5) (1 2 1) (1 4 1) (1 4 4))

You want an algorithm that takes two input sequences of sequences and does this:
Take one sequence from each input sequence so that you have two sequences, s1 and s2
For each elem in s2 produce a sequence of s1 with elem appended to it
Repeat 1. until one of the two input sequences has no more sequences left
In Clojure:
(mapcat (fn [s1 s2]
(map (fn [elem]
(conj s1 elem)) s2))
acc pairs)

Note: your algorithm requires appending to collections - it is better to use a collection type that supports fast access to the back (like a vector)
(def acc '([1 2] [1 4])) ;; notice the inner collections are vectors
(def pairs '([5 1] [1 4]))
(defn zipp
[c1 c2]
(mapcat (fn [c3 c4]
(map (partial conj c3) c4)) ;; change this line for lists!
c1
c2))
(zipp acc pairs)
;; => ([1 2 5] [1 2 1] [1 4 1] [1 4 4])
If you must work with list's, you can change the line marked above to:
(map (partial conj (into [] c3)) c4))
It's rather ugly, IMO.

When mapping over nested data structures, for is often simpler.
user>
(defn unfolder
[acc pairs]
(for [combination (map list acc pairs)
tail (second combination)]
(conj (vec (first combination)) tail)))
#'user/unfolder
user> (unfolder '((1 2) (1 4)) '((5 1) (1 4)))
([1 2 5] [1 2 1] [1 4 1] [1 4 4])

Related

Clojure - using map recursively

If I have a list, I can use map to apply a function to each item of the list.
(map sqrt (list 1 4 9))
(1 2 3)
I can also use map in front of a list of lists:
(map count (list (list 1 2 3) (list 4 5)))
(4 5)
Now is there a way to apply sqrt to each number in the list of lists? I want to start from
(list (list 1 4 9) (list 16 25))
and obtain
((1 2 3)(4 5))
However, the following does not seem to work,
(map (map sqrt) (list (list 1 4 9) (list 16 25)))
nor the following.
(map (fn [x] (map sqrt x)) (list (list 1 4 9) (list 16 25)))
Why? (And how do I solve this?)
Your second to last version "nearly" works. Clojure has no automatic
currying, so (map sqrt) is not partial application, but (map sqrt)
returns a transducer, which takes one argument and returns a function
with three different arities - so running your code there will give you
back a function for each list of numbers.
To make that work, you can use partial:
user=> (map (partial map sqrt) (list (list 1 4 9) (list 16 25)))
((1 2 3) (4 5))
And of course there is the obligatory specter answer:
user=> (transform [ALL ALL] sqrt '((1 4 9)(16 25)))
((1 2 3) (4 5))
You can write recursive function for this task:
(defn deep-map [f seq1]
(cond (empty? seq1) nil
(sequential? (first seq1))
(cons (deep-map f (first seq1))
(deep-map f (rest seq1)))
:else (cons (f (first seq1))
(deep-map f (rest seq1)))))
Example:
(deep-map #(Math/sqrt %) '((1 4 9) (16 25 36)))
=> ((1.0 2.0 3.0) (4.0 5.0 6.0))
Or you can use clojure.walk and function postwalk:
(clojure.walk/postwalk
#(if (number? %) (Math/sqrt %) %)
'((1 4 9) (16 25 36)))
=> ((1.0 2.0 3.0) (4.0 5.0 6.0))
The function map is closely related to the function for, which I think is sometimes easier to use. Here is how I would solve this problem:
(let [matrix [[1 4 9]
[16 25]]
result (vec (for [row matrix]
(vec (for [num row]
(Math/sqrt num)))))]
result)
with result:
result =>
[[1.0 2.0 3.0]
[4.0 5.0]]
If you remove the two (vec ...) bits, you'll see the same result but for normally returns a lazy sequence.
#MartinPuda's answer is right.
The tail call recursive version is here:
(defn map* [f sq & {:keys [acc] :or {acc '()}}]
(cond (empty? sq) (vec (reverse acc))
(sequential? (first sq)) (map* f
(rest sq)
:acc (cons (map* f (first sq)) acc))
:else (map* f (rest sq) :acc (cons (f (first sq)) acc))))
By tradition in lisp, such recursively into the nested structure going functions are fnname* (marked by an asterisk at the end).
acc accumulates the result nested tree which is constructed by cons.
In your case this would be:
(map* Math/sqrt (list (list 1 4 9) (list 16 25)))
Test with:
(map* (partial + 1) '[1 2 [3 4 [5] 6] 7 [8 [9]]])
;; => [2 3 [4 5 [6] 7] 8 [9 [10]]]

Concatenate elements to list by using loop in clojure?

I am trying to get into Lisps and FP by trying out the 99 problems.
Here is the problem statement (Problem 15)
Replicate the elements of a list a given number of times.
I have come up with the following code which simply returns an empty list []
I am unable to figure out why my code doesn't work and would really appreciate some help.
(defn replicateList "Replicates each element of the list n times" [l n]
(loop [initList l returnList []]
(if (empty? initList)
returnList
(let [[head & rest] initList]
(loop [x 0]
(when (< x n)
(conj returnList head)
(recur (inc x))))
(recur rest returnList)))))
(defn -main
"Main" []
(test/is (=
(replicateList [1 2] 2)
[1 1 2 2])
"Failed basic test")
)
copying my comment to answer:
this line: (conj returnList head) doesn't modify returnlist, rather it just drops the result in your case. You should restructure your program to pass the accumulated list further to the next iteration. But there are better ways to do this in clojure. Like (defn replicate-list [data times] (apply concat (repeat times data)))
If you still need the loop/recur version for educational reasons, i would go with this:
(defn replicate-list [data times]
(loop [[h & t :as input] data times times result []]
(if-not (pos? times)
result
(if (empty? input)
(recur data (dec times) result)
(recur t times (conj result h))))))
user> (replicate-list [1 2 3] 3)
;;=> [1 2 3 1 2 3 1 2 3]
user> (replicate-list [ ] 2)
;;=> []
user> (replicate-list [1 2 3] -1)
;;=> []
update
based on the clarified question, the simplest way to do this is
(defn replicate-list [data times]
(mapcat (partial repeat times) data))
user> (replicate-list [1 2 3] 3)
;;=> (1 1 1 2 2 2 3 3 3)
and the loop/recur variant:
(defn replicate-list [data times]
(loop [[h & t :as data] data n 0 res []]
(cond (empty? data) res
(>= n times) (recur t 0 res)
:else (recur data (inc n) (conj res h)))))
user> (replicate-list [1 2 3] 3)
;;=> [1 1 1 2 2 2 3 3 3]
user> (replicate-list [1 2 3] 0)
;;=> []
user> (replicate-list [] 10)
;;=> []
Here is a version based on the original post, with minimal modifications:
;; Based on the original version posted
(defn replicateList "Replicates each element of the list n times" [l n]
(loop [initList l returnList []]
(if (empty? initList)
returnList
(let [[head & rest] initList]
(recur
rest
(loop [inner-returnList returnList
x 0]
(if (< x n)
(recur (conj inner-returnList head) (inc x))
inner-returnList)))))))
Please keep in mind that Clojure is mainly a functional language, meaning that most functions produce their results as a new return value instead of updating in place. So, as pointed out in the comment, the line (conj returnList head) will not have an effect, because it's return value is ignored.
The above version works, but does not really take advantage of Clojure's sequence processing facilities. So here are two other suggestions for solving your problem:
;; Using lazy seqs and reduce
(defn replicateList2 [l n]
(reduce into [] (map #(take n (repeat %)) l)))
;; Yet another way using transducers
(defn replicateList3 [l n]
(transduce
(comp (map #(take n (repeat %)))
cat
)
conj
[]
l))
One thing is not clear about your question though: From your implementation, it looks like you want to create a new list where each element is repeated n times, e.g.
playground.replicate> (replicateList [1 2 3] 4)
[1 1 1 1 2 2 2 2 3 3 3 3]
But if you would instead like this result
playground.replicate> (replicateList [1 2 3] 4)
[1 2 3 1 2 3 1 2 3 1 2 3]
the answer to your question will be different.
If you want to learn idiomatic Clojure you should try to find a solution without such low level facilities as loop. Rather try to combine higher level functions like take, repeat, repeatedly. If you're feeling adventurous you might throw in laziness as well. Clojure's sequences are lazy, that is they get evaluated only when needed.
One example I came up with would be
(defn repeat-list-items [l n]
(lazy-seq
(when-let [s (seq l)]
(concat (repeat n (first l))
(repeat-list-items (next l) n)))))
Please also note the common naming with kebab-case
This seems to do what you want pretty well and works for an unlimited input (see the call (range) below), too:
experi.core> (def l [:a :b :c])
#'experi.core/
experi.core> (repeat-list-items l 2)
(:a :a :b :b :c :c)
experi.core> (repeat-list-items l 0)
()
experi.core> (repeat-list-items l 1)
(:a :b :c)
experi.core> (take 10 (drop 10000 (repeat-list-items (range) 4)))
(2500 2500 2500 2500 2501 2501 2501 2501 2502 2502)

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)

Clojure - how to do reductions function but drop state?

If I use the reductions function like so:
(reductions + [1 2 3 4 5])
Then I get
(1 3 6 10 15)
Which is great - but I'd like to apply a binary function in the same way without the state being carried forward - something like
(magic-hof + [1 2 3 4 5])
leads to
(1 3 5 7 9)
ie it returns the operation applied to the first pair, then steps 1 to the next pair.
Can someone tell me the higher-order function I'm looking for? (Something like reductions)
This is my (non-working) go at it:
(defn thisfunc [a b] [(+ a b) b])
(reduce thisfunc [1 2 3 4 5])
You can do it with map:
(map f coll (rest coll))
And if you want a function:
(defn map-pairwise [f coll]
(map f coll (rest coll)))
And if you really need the first element to remain untouched (thanx to juan.facorro's comment):
(defn magic-hof [f [x & xs :as s]]
(cons x (map f s xs)))
partition will group your seq:
user> (->> [1 2 3 4 5] (partition 2 1) (map #(apply + %)) (cons 1))
(1 3 5 7 9)
So, you want to apply a function to subsequent pairs of elements?
(defn pairwise-apply
[f sq]
(when (seq sq)
(->> (map f sq (next sq))
(cons (first sq)))))
Let's try it:
(pairwise-apply + (range 1 6))
;; => (1 3 5 7 9)
This is sufficient:
(#(map + (cons 0 %) %) [1 2 3 4 5])
;; => (1 3 5 7 9)

Need a similar function to disj but for a list in clojure. Is it overall possible?

I need to traverse a list and do some calculations with every element and the elements excluding that element. For example, having a list (1 2 3 1), I need pairs (1) (2 3 1), (2) (1 3 1), (3) (1 2 1) and (1) (2 3 1).
(...) with every element and the elements excluding that element.
With every element sounds like a map. Excluding that element sounds like a filter. Let's start with the latter.
user=> (filter #(not= % 1) '(1 2 3))
(2 3)
Great. Now let's try to map it over all elements.
user=> (let [coll '(1 2 3)] (map (fn [elem] (filter #(not= % elem) coll)) coll))
((2 3) (1 3) (1 2))
Creating actual pairs is left as an exercise for the reader. Hint: modify the closure used in map.
Keep in mind that the solution suggested above should work fine for short lists but it has a complexity of O(n²). Another issue is the fact that collections with duplicates aren't handled correctly.
Let's take a recursive approach instead. We'll base the recursion on loop and recur.
(defn pairs [coll]
(loop [ahead coll behind [] answer []]
(if (empty? ahead)
answer
(let [[current & remaining] ahead]
(recur remaining
(conj behind current)
(conj answer [(list current)
(concat behind remaining)]))))))
A trivial example:
user=> (pairs '(1 2 3))
[[(1) (2 3)] [(2) (1 3)] [(3) (1 2)]]
A vector with duplicates:
user=> (pairs [1 5 6 5])
[[(1) (5 6 5)] [(5) (1 6 5)] [(6) (1 5 5)] [(5) (1 5 6)]]
Seems a job for a list comprehension:
(defn gimme-pairs [coll]
(for [x coll]
[(list x) (remove #{x} coll)]))
user=> (gimme-pairs [1 2 3])
([(1) (2 3)] [(2) (1 3)] [(3) (1 2)])
I would actually skip creating a list for the single element, which would make the code even easier:
(defn gimme-pairs [coll]
(for [x coll]
[x (remove #{x} coll)]))
user=> (gimme-pairs [1 2 3])
([1 (2 3)] [2 (1 3)] [3 (1 2)])
If you need to keep duplicates then you can use an indexed collection:
(defn gimme-pairs [coll]
(let [indexed (map-indexed vector coll)
remove-index (partial map second)]
(for [[i x] indexed]
[x (remove-index (remove #{[i x]} indexed))])))
user=> (gimme-pairs [1 2 3 1])
([1 (2 3 1)] [2 (1 3 1)] [3 (1 2 1)] [1 (1 2 3)])
(def l [1 2 3])
(first (reduce (fn [[res ll] e]
[(conj res [(list e) (rest ll)])
(conj (vec (rest ll)) e)])
[[] l] l))
=> [[(1) (2 3)] [(2) (3 1)] [(3) (1 2)]]