Clojure - using map recursively - clojure

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

Related

function flatten in Clojure

When translate a function flatten from Scheme to Clojure, I have encountered
an error "Execution error (IllegalArgumentException)", Please feel free to comment.
Clojure (Encounter error)
(defn flatten [x]
(cond
(empty? x) '()
(not (coll? x)) (list x)
:else (conj (flatten (first x)) (flatten (rest x)))))
(flatten '((1) 2 ((3 4) 5) ((())) (((6))) 7 8 ()))
Scheme
> (define (flatten x)
(cond ((null? x) '())
((not (pair? x)) (list x))
(else (append (flatten (car x))
(flatten (cdr x))))))
> (flatten '((1) 2 ((3 4) 5) ((())) (((6))) 7 8 ()))
(1 2 3 4 5 6 7 8)
Here is an implementation that works for me
(defn flatten [x]
(cond
(not (coll? x)) (list x)
(empty? x) '()
:else (concat (flatten (first x)) (flatten (rest x)))))
(comment
(flatten '((1) 2 ((3 4) 5) ((())) (((6))) 7 8 ())))
;returns (1 2 3 4 5 6 7 8)
The only difference is that I put first the (not (coll? x)) and then the empty? (because (empty? 3) will throw an error)
The other change is the concat instead of conj. I don't think it's recommended to use concat because it can throw a Stack Overflow Error (see : https://stuartsierra.com/2015/04/26/clojure-donts-concat) but it works in this case ...
One more version, based on Alan Thompson's solution:
(defn flat [data]
(reduce (fn [result e]
(if (not (sequential? e))
(conj result e)
(into result (flat e))))
[] data))
Tests:
(clojure.test/are [result arg]
(= result (flat arg))
[1 2 3] [1 2 3]
[1 2 3] [1 [2 3]]
[1 2 3] [1 [2 [3]]]
[0 1 2 3 4 5 6 7] [[0] [1 2 3] [4 5 [6 7]]])
=> true
Here is an alternate version that may be a bit more straightforward:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn flatten
[data]
(loop [result []
items data]
(if (empty? items)
result
(let [item (first items)
items-next (rest items)]
(if (not (sequential? item))
(recur
(conj result item)
items-next)
(recur
(into result (flatten item))
items-next))))))
(dotest
(is= (flatten [1 2 3]) [1 2 3])
(is= (flatten [1 [2 3]]) [1 2 3])
(is= (flatten [1 [2 [3]]]) [1 2 3])
(is= (flatten [[0] [1 2 3] [4 5 [6 7]]]) [0 1 2 3 4 5 6 7])
; Cannot flatten a scalar value - we don't want (flatten 3) => [3]
(throws? (flatten 3)))
Note that we avoid tricks like wrapping every scalar value in a list, so we don't get the non-intuitive result (flatten 3) => [3].
Build using my favorite template project.

clojure - combine to structures to get flatter result

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

Partition a seq by a "windowing" predicate in Clojure

I would like to "chunk" a seq into subseqs the same as partition-by, except that the function is not applied to each individual element, but to a range of elements.
So, for example:
(gather (fn [a b] (> (- b a) 2))
[1 4 5 8 9 10 15 20 21])
would result in:
[[1] [4 5] [8 9 10] [15] [20 21]]
Likewise:
(defn f [a b] (> (- b a) 2))
(gather f [1 2 3 4]) ;; => [[1 2 3] [4]]
(gather f [1 2 3 4 5 6 7 8 9]) ;; => [[1 2 3] [4 5 6] [7 8 9]]
The idea is that I apply the start of the list and the next element to the function, and if the function returns true we partition the current head of the list up to that point into a new partition.
I've written this:
(defn gather
[pred? lst]
(loop [acc [] cur [] l lst]
(let [a (first cur)
b (first l)
nxt (conj cur b)
rst (rest l)]
(cond
(empty? l) (conj acc cur)
(empty? cur) (recur acc nxt rst)
((complement pred?) a b) (recur acc nxt rst)
:else (recur (conj acc cur) [b] rst)))))
and it works, but I know there's a simpler way. My question is:
Is there a built in function to do this where this function would be unnecessary? If not, is there a more idiomatic (or simpler) solution that I have overlooked? Something combining reduce and take-while?
Thanks.
Original interpretation of question
We (all) seemed to have misinterpreted your question as wanting to start a new partition whenever the predicate held for consecutive elements.
Yet another, lazy, built on partition-by
(defn partition-between [pred? coll]
(let [switch (reductions not= true (map pred? coll (rest coll)))]
(map (partial map first) (partition-by second (map list coll switch)))))
(partition-between (fn [a b] (> (- b a) 2)) [1 4 5 8 9 10 15 20 21])
;=> ((1) (4 5) (8 9 10) (15) (20 21))
Actual Question
The actual question asks us to start a new partition whenever pred? holds for the beginning of the current partition and the current element. For this we can just rip off partition-by with a few tweaks to its source.
(defn gather [pred? coll]
(lazy-seq
(when-let [s (seq coll)]
(let [fst (first s)
run (cons fst (take-while #((complement pred?) fst %) (next s)))]
(cons run (gather pred? (seq (drop (count run) s))))))))
(gather (fn [a b] (> (- b a) 2)) [1 4 5 8 9 10 15 20 21])
;=> ((1) (4 5) (8 9 10) (15) (20 21))
(gather (fn [a b] (> (- b a) 2)) [1 2 3 4])
;=> ((1 2 3) (4))
(gather (fn [a b] (> (- b a) 2)) [1 2 3 4 5 6 7 8 9])
;=> ((1 2 3) (4 5 6) (7 8 9))
Since you need to have the information from previous or next elements than the one you are currently deciding on, a partition of pairs with a reduce could do the trick in this case.
This is what I came up with after some iterations:
(defn gather [pred s]
(->> (partition 2 1 (repeat nil) s) ; partition the sequence and if necessary
; fill the last partition with nils
(reduce (fn [acc [x :as s]]
(let [n (dec (count acc))
acc (update-in acc [n] conj x)]
(if (apply pred s)
(conj acc [])
acc)))
[[]])))
(gather (fn [a b] (when (and a b) (> (- b a) 2)))
[1 4 5 8 9 10 15 20 21])
;= [[1] [4 5] [8 9 10] [15] [20 21]]
The basic idea is to make partitions of the number of elements the predicate function takes, filling the last partition with nils if necessary. The function then reduces each partition by determining if the predicate is met, if so then the first element in the partition is added to the current group and a new group is created. Since the last partition could have been filled with nulls, the predicate has to be modified.
Tow possible improvements to this function would be to let the user:
Define the value to fill the last partition, so the reducing function could check if any of the elements in the partition is this value.
Specify the arity of the predicate, thus allowing to determine the grouping taking into account the current and the next n elements.
I wrote this some time ago in useful:
(defn partition-between [split? coll]
(lazy-seq
(when-let [[x & more] (seq coll)]
(lazy-loop [items [x], coll more]
(if-let [[x & more] (seq coll)]
(if (split? [(peek items) x])
(cons items (lazy-recur [x] more))
(lazy-recur (conj items x) more))
[items])))))
It uses lazy-loop, which is just a way to write lazy-seq expressions that look like loop/recur, but I hope it's fairly clear.
I linked to a historical version of the function, because later I realized there's a more general function that you can use to implement partition-between, or partition-by, or indeed lots of other sequential functions. These days the implementation is much shorter, but it's less obvious what's going on if you're not familiar with the more general function I called glue:
(defn partition-between [split? coll]
(glue conj []
(fn [v x]
(not (split? [(peek v) x])))
(constantly false)
coll))
Note that both of these solutions are lazy, which at the time I'm writing this is not true of any of the other solutions in this thread.
Here is one way, with steps split up. It can be narrowed down to fewer statements.
(def l [1 4 5 8 9 10 15 20 21])
(defn reduce_fn [f x y]
(cond
(f (last (last x)) y) (conj x [y])
:else (conj (vec (butlast x)) (conj (last x) y)) )
)
(def reduce_fn1 (partial reduce_fn #(> (- %2 %1) 2)))
(reduce reduce_fn1 [[(first l)]] (rest l))
keep-indexed is a wonderful function. Given a function f and a vector lst,
(keep-indexed (fn [idx it] (if (apply f it) idx))
(partition 2 1 lst)))
(0 2 5 6)
this returns the indices after which you want to split. Let's increment them and tack a 0 at the front:
(cons 0 (map inc (.....)))
(0 1 3 6 7)
Partition these to get ranges:
(partition 2 1 nil (....))
((0 1) (1 3) (3 6) (6 7) (7))
Now use these to generate subvecs:
(map (partial apply subvec lst) ....)
([1] [4 5] [8 9 10] [15] [20 21])
Putting it all together:
(defn gather
[f lst]
(let [indices (cons 0 (map inc
(keep-indexed (fn [idx it]
(if (apply f it) idx))
(partition 2 1 lst))))]
(map (partial apply subvec (vec lst))
(partition 2 1 nil indices))))
(gather #(> (- %2 %) 2) '(1 4 5 8 9 10 15 20 21))
([1] [4 5] [8 9 10] [15] [20 21])

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)

Clojure: How to generate a 'trie'?

Given the following...
(def inTree
'((1 2)
(1 2 3)
(1 2 4 5 9)
(1 2 4 10 15)
(1 2 4 20 25)))
How would you transform it to this trie?
(def outTrie
'(1
(2 ()
(3 ())
(4 (5
(9 ()))
(10
(15 ()))
(20
(25 ()))))))
Here's a cleaned up solution. This fixes a bug Brian's add-to-trie method since it's currently dependent upon you inserting the seqs in increasing-length order. It also allows querying the trie by prefix, which is a common use case.
Note the memory usage here is higher since it stores the values in the leaf nodes of the trie so you can perform searches.
(defn add-to-trie [trie x]
(assoc-in trie x (merge (get-in trie x) {:val x :terminal true})))
(defn in-trie? [trie x]
"Returns true if the value x exists in the specified trie."
(:terminal (get-in trie x) false))
(defn prefix-matches [trie prefix]
"Returns a list of matches with the prefix specified in the trie specified."
(keep :val (tree-seq map? vals (get-in trie prefix))))
(defn build-trie [coll]
"Builds a trie over the values in the specified seq coll."
(reduce add-to-trie {} coll))
Lists are very clumsy here, not to mention inefficient. In Clojure it's more idiomatic to use vectors and hash-maps and sets when appropriate. Using hash-maps:
(def in-tree
'((1 2)
(1 2 3)
(1 2 4 5 9)
(1 2 4 10 15)
(1 2 4 20 25)))
(defn add-to-trie [trie x]
(assoc-in trie `(~#x :terminal) true))
(defn in-trie? [trie x]
(get-in trie `(~#x :terminal)))
If you wanted it to print sorted you could use sorted-maps instead, but you'd have to write your own version of assoc-in that used sorted maps the whole way down. In any case:
user> (def trie (reduce add-to-trie {} in-tree))
#'user/trie
user> trie
{1 {2 {4 {20 {25 {:terminal true}}, 10 {15 {:terminal true}}, 5 {9 {:terminal true}}}, 3 {:terminal true}, :terminal true}}}
user> (in-trie? trie '(1 2))
true
user> (in-trie? trie '(1 2 4))
nil
user> (in-trie? trie '(1 2 4 20 25))
true
As a general approach, here's what I would do:
Write a few functions to create a trie and to insert new elements into a trie.
Create a new trie.
Iterate through the input list and insert each element into the trie.
This problem lends itself very well to a recursive implementation. I would aim for that if possible.
I'm sure there is a prettier way (there was! see Brian's answer it is better):
(defn find-in-trie
"Finds a sub trie that matches an item, eg:
user=> (find-in-trie '(1 (2) (3 (2))) 3)
(3 (2))"
[tr item]
(first (for [ll (rest tr) :when (= (first ll) item)] ll)))
(defn add-to-trie
"Returns a new trie, the result of adding se to tr, eg:
user=> (add-to-trie nil '(1 2))
(1 (2))"
[tr se]
(cond
(empty? se) tr
(empty? tr) (add-to-trie (list (first se)) (rest se))
:else (if-let [st (find-in-trie tr (first se))]
(cons (first tr)
(cons (add-to-trie st (rest se))
(filter (partial not= st) (rest tr))))
(cons (first tr)
(cons (add-to-trie (list (first se)) (rest se))
(rest tr))))))
(def in '((1 2)
(1 2 3)
(1 2 4 5 9)
(1 2 4 10 15)
(1 2 4 20 25)))
(reduce add-to-trie '(nil) in)
-> (nil (1 (2 (4 (20 (25)) (10 (15)) (5 (9))) (3))))
Note that I've chosen to use nil as the root node and have not bothered keeping empty lists to signify no children. Actually doing it this way is not correct as it does not preserve substring identity.