Clojure beginner - implement flatten, trouble with 'let' - clojure

New to Clojure.
Input - ["a" ["b" "c"] "d"]
Expected output - ["a" "b" "c" "d"]
What I'm trying to do - create an empty vector ('result'), then do two doseq's on the input collection to fill 'result' up, finally return the filled up 'result'. However the function returns an empty vector. What am I doing wrong?
(flat ["a" ["b" "c"] "d"])
(defn flat [arr]
(let [result []]
(doseq [element arr]
(if (coll? element) (doseq [element2 element] (conj result element2))
(conj result element))) result))

As others have pointed out, you can't mutate result. If you really did want to implement your function with mutation you'd need an atom, which you can mutate with swap!
(defn flat [arr]
(let [result (atom [])]
(doseq [element arr]
(if (coll? element) (doseq [element2 element] (swap! result conj element2))
(swap! result conj element)))
#result))
Notice however, that this only gives you a single level of flattening, which you can accomplish simply with
(apply concat <your seq>)
A simple, recursive, multilevel flatten is:
(defn flat [x] (if (coll? x) (mapcat flat x) [x]))

#!/usr/bin/env boot
(def inp ["a" "b" ["c" "d" "e" ["f" "g" "h"] "i"] "j" "k"])
(defn flat
([xs] (flat xs []))
([xs acc]
(if (empty? xs) acc
(if (vector? (first xs))
(flat (rest xs) (flat (first xs) acc))
(recur (rest xs) (conj acc (first xs)))))))
(println (flat inp)) ;[a b c d e f g h i j k]
The basic idea is to check if first element is a list, if so recurse that list (flat (first xs) acc) adding each element to the accumulator and then proceed with rest of the list giving (flat (rest xs) (flat (first xs) acc)). Else just recur individual elements.
We can use other constructs like let, cond as well.

If you want a fast version of flatten, see clojure.core.reducers/flatten.
(require '[clojure.core.reducers :as r])
(defn rflatten [coll] (into [] (r/flatten coll)))

Related

How to fix recursive search through list

I'm currently trying to learn Clojure. But I am having trouble creating a function that recursively searches through each element of the list and returns the number of "a"'s present in the list.
I have already figured out how to do it iteratively, but I am having trouble doing it recursively. I have tried changing "seq" with "empty?" but that hasn't worked either.
(defn recursive-a [& lst]
(if (seq lst)
(if (= (first lst) "a")
(+ 1 (recursive-a (pop (lst))))
(+ 0 (recursive-a (pop (lst)))))
0))
Welcome to stack overflow community.
You code is fine, except that you made a few minor mistakes.
Firstly, there is one extra pair of braces around your lst parameter that you forward to recursive function. In LISP languages, braces mean evaluation of function. So, first you should remove those.
Second thing is the & parameter syntactic sugar. You do not want to use that until you are certain how it affects your code.
With these changes, the code is as follows:
(defn recursive-a [lst]
(if (seq lst)
(if (= (first lst) "a")
(+ 1 (recursive-a (pop lst)))
(+ 0 (recursive-a (pop lst))))
0))
(recursive-a (list "a" "b" "c"))
You can run it in a web environment: https://repl.it/languages/clojure
Welcome to Stack Overflow.
By invoking recursive-a explicitly the original implementation consumes stack with each recursion. If a sufficiently large list is provided as input this function will eventually exhaust the stack and crash. There are a several ways to work around this.
One of the classic Lisp-y methods for handling situations such as this is to provide a second implementation of the function which passes the running count as an input argument to the "inner" function:
(defn recursive-a-inner [cnt lst]
(cond
(seq lst) (cond
(= (first lst) "a") (recur (inc cnt) (rest lst))
:else (recur cnt (rest lst)))
:else cnt))
(defn recursive-a [& lst]
(recursive-a-inner 0 lst))
By doing this the "inner" version allows the recursion to be pushed into tail position so that Clojure's recur keyword can be used. It's not quite as clean an implementation as the original but it has the advantage that it won't blow up the stack.
Another method for handling this is to use Clojure's loop-ing, which allows recursion within the body of a function. The result is much the same as the "inner" function above:
(defn recursive-a [& lp]
(loop [cnt 0
lst lp]
(cond
(seq lst) (cond
(= (first lst) "a") (recur (inc cnt) (rest lst))
:else (recur cnt (rest lst)))
:else cnt)))
And if we drop the requirement for explicit recursion we can make this a bit simpler:
(defn not-recursive-a [& lst]
(apply + (map #(if (= % "a") 1 0) lst)))
Best of luck.
In the spirit of learning:
You can use & or not. Both are fine. The difference is how you would then call your function, and you would have to remember to use apply when recurring.
Also, simply use first and rest. They are both safe and will work on both nil and empty lists, returning nil and empty list respectively:
(first []) ;; -> nil
(first nil) ;; -> nil
(rest []) ;; -> ()
(rest nil) ;; -> ()
So here is how I would re-work your idea:
;; With '&'
(defn count-a [& lst]
(if-let [a (first lst)]
(+ (if (= a "a") 1 0)
(apply count-a (rest lst))) ;; use 'apply' here
0))
;; call with variable args, *not* a list
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(if-let [a (first lst)]
(+ (if (= a "a") 1 0)
(count-a (rest lst)))
0))
;; call with a single arg: a vector (could be a list or other )
(count-a ["a" "b" "a" "c"])
However, these are not safe, because they don't use tail-recursion, and so if your list is large, you will blow your stack!
So, we use recur. But if you don't want to define an additional "helper" function, you can instead use loop as the "recur" target:
;; With '&'
(defn count-a [& lst]
(loop [c 0 lst lst] ;; 'recur' will loop back to this point
(if-let [a (first lst)]
(recur (if (= a "a") (inc c) c) (rest lst))
c)))
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(loop [c 0 lst lst]
(if-let [a (first lst)]
(recur (if (= a "a") (inc c) c) (rest lst))
c)))
(count-a ["a" "b" "a" "c"])
All that being said, this is the one I also would use:
;; With '&'
(defn count-a [& lst]
(count (filter #(= % "a") lst)))
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(count (filter #(= % "a") lst)))
(count-a ["a" "b" "a" "c"])

Append to a vector in a function

I have two columns (vectors) of different length and want to create a new vector of rows (if the column has enough elements). I'm trying to create a new vector (see failed attempt below). In Java this would involve the steps: iterate vector, check condition, append to vector, return vector. Do I need recursion here? I'm sure this is not difficult to solve, but it's very different than procedural code.
(defn rowmaker [colA colB]
"create a row of two columns of possibly different length"
(let [mia (map-indexed vector colA)
rows []]
(doseq [[i elA] mia]
;append if col has enough elements
(if (< i (count colA)) (vec (concat rows elA))) ; ! can't append to rows
(if (< i (count colB)) (vec (concat rows (nth colB i)))
;return rows
rows)))
Expected example input/output
(rowMaker ["A1"] ["B1" "B2"])
; => [["A1" "B1“] [“" "B2"]]
(defn rowMaker [colA colB]
"create a row from two columns"
(let [ca (count colA) cb (count colB)
c (max ca cb)
colA (concat colA (repeat (- c ca) ""))
colB (concat colB (repeat (- c cb) ""))]
(map vector colA colB)))
(defn rowmaker
[cols]
(->> cols
(map #(concat % (repeat "")))
(apply map vector)
(take (->> cols
(map count)
(apply max)))))
I prefer recursion to counting the number of items in collections. Here is my solution.
(defn row-maker
[col-a col-b]
(loop [acc []
as (seq col-a)
bs (seq col-b)]
(if (or as bs)
(recur (conj acc [(or (first as) "") (or (first bs) "")])
(next as)
(next bs))
acc)))
The following does the trick with the given example:
(defn rowMaker [v1 v2]
(mapv vector (concat v1 (repeat "")) v2))
(rowMaker ["A1"] ["B1" "B2"])
;[["A1" "B1"] ["" "B2"]]
However, it doesn't work the other way round:
(rowMaker ["B1" "B2"] ["A1"])
;[["B1" "A1"]]
To make it work both ways, we are going to have to write a version of mapv that fills in for sterile sequences so long as any sequence is fertile. Here is a corresponding lazy version for map, which will work for infinite sequences too:
(defn map-filler [filler f & colls]
(let [filler (vec filler)
colls (vec colls)
live-coll-map (->> colls
(map-indexed vector)
(filter (comp seq second))
(into {}))
split (fn [lcm] (reduce
(fn [[x xm] [i coll]]
(let [[c & cs] coll]
[(assoc x i c) (if cs (assoc xm i cs) xm)]))
[filler {}]
lcm))]
((fn expostulate [lcm]
(lazy-seq
(when (seq lcm)
(let [[this thoses] (split lcm)]
(cons (apply f this) (expostulate thoses))))))
live-coll-map)))
The idea is that you supply a filler sequence with one entry for each of the collections that follow. So we can now define your required rowmaker function thus:
(defn rowmaker [& colls]
(apply map-filler (repeat (count colls) "") vector colls))
This will take any number of collections, and will fill in blank strings for exhausted collections.
(rowmaker ["A1"] ["B1" "B2"])
;(["A1" "B1"] ["" "B2"])
(rowmaker ["B1" "B2"] ["A1"])
;(["B1" "A1"] ["B2" ""])
It works!
(defn make-row
[cola colb r]
(let [pad ""]
(cond
(and (not (empty? cola))
(not (empty? colb))) (recur (rest cola)
(rest colb)
(conj r [(first cola) (first colb)]))
(and (not (empty? cola))
(empty? colb)) (recur (rest cola)
(rest colb)
(conj r [(first cola) pad]))
(and (empty? cola)
(not (empty? colb))) (recur (rest cola)
(rest colb)
(conj r [pad (first colb)]))
:else r)))

Checking odd parity in clojure

I have the following functions that check for odd parity in sequence
(defn countOf[a-seq elem]
(loop [number 0 currentSeq a-seq]
(cond (empty? currentSeq) number
(= (first currentSeq) elem) (recur (inc number) (rest currentSeq))
:else (recur number (rest currentSeq))
)
)
)
(defn filteredSeq[a-seq elemToRemove]
(remove (set (vector (first a-seq))) a-seq)
)
(defn parity [a-seq]
(loop [resultset [] currentSeq a-seq]
(cond (empty? currentSeq) (set resultset)
(odd? (countOf currentSeq (first currentSeq))) (recur (concat resultset (vector(first currentSeq))) (filteredSeq currentSeq (first currentSeq)))
:else (recur resultset (filteredSeq currentSeq (first currentSeq)))
)
)
)
for example (parity [1 1 1 2 2 3]) -> (1 3) that is it picks odd number of elements from a sequence.
Is there a better way to achieve this?
How can this be done with reduce function of clojure
First, I decided to make more idiomatic versions of your code, so I could really see what it was doing:
;; idiomatic naming
;; no need to rewrite count and filter for this code
;; putting item and collection in idiomatic argument order
(defn count-of [elem a-seq]
(count (filter #(= elem %) a-seq)))
;; idiomatic naming
;; putting item and collection in idiomatic argument order
;; actually used the elem-to-remove argument
(defn filtered-seq [elem-to-remove a-seq]
(remove #(= elem-to-remove %) a-seq))
;; idiomatic naming
;; if you want a set, use a set from the beginning
;; destructuring rather than repeated usage of first
;; use rest to recur when the first item is guaranteed to be dropped
(defn idiomatic-parity [a-seq]
(loop [result-set #{}
[elem & others :as current-seq] a-seq]
(cond (empty? current-seq)
result-set
(odd? (count-of elem current-seq))
(recur (conj result-set elem) (filtered-seq elem others))
:else
(recur result-set (filtered-seq elem others)))))
Next, as requested, a version that uses reduce to accumulate the result:
;; mapcat allows us to return 0 or more results for each input
(defn reducing-parity [a-seq]
(set
(mapcat
(fn [[k v]]
(when (odd? v) [k]))
(reduce (fn [result item]
(update-in result [item] (fnil inc 0)))
{}
a-seq))))
But, reading over this, I notice that the reduce is just frequencies, a built in clojure function. And my mapcat was really just a hand-rolled keep, another built in.
(defn most-idiomatic-parity [a-seq]
(set
(keep
(fn [[k v]]
(when (odd? v) k))
(frequencies a-seq))))
In Clojure we can refine our code, and as we recognize places where our logic replicates the built in functionality, we can simplify the code and make it more clear. Also, there is a good chance the built in is better optimized than our own work-alikes.
Is there a better way to achieve this?
(defn parity [coll]
(->> coll
frequencies
(filter (fn [[_ v]] (odd? v)))
(map first)
set))
For example,
(parity [1 1 1 2 1 2 1 3])
;#{1 3}
How can this be done with reduce function of clojure.
We can use reduce to rewrite frequencies:
(defn frequencies [coll]
(reduce
(fn [acc x] (assoc acc x (inc (get acc x 0))))
{}
coll))
... and again to implement parity in terms of it:
(defn parity [coll]
(let [freqs (frequencies coll)]
(reduce (fn [s [k v]] (if (odd? v) (conj s k) s)) #{} freqs)))

Grouping words and more

I'm working on a project to learn Clojure in practice. I'm doing well, but sometimes I get stuck. This time I need to transform sequence of the form:
[":keyword0" "word0" "word1" ":keyword1" "word2" "word3"]
into:
[[:keyword0 "word0" "word1"] [:keyword1 "word2" "word3"]]
I'm trying for at least two hours, but I know not so many Clojure functions to compose something useful to solve the problem in functional manner.
I think that this transformation should include some partition, here is my attempt:
(partition-by (fn [x] (.startsWith x ":")) *1)
But the result looks like this:
((":keyword0") ("word1" "word2") (":keyword1") ("word3" "word4"))
Now I should group it again... I doubt that I'm doing right things here... Also, I need to convert strings (only those that begin with :) into keywords. I think this combination should work:
(keyword (subs ":keyword0" 1))
How to write a function which performs the transformation in most idiomatic way?
Here is a high performance version, using reduce
(reduce (fn [acc next]
(if (.startsWith next ":")
(conj acc [(-> next (subs 1) keyword)])
(conj (pop acc) (conj (peek acc)
next))))
[] data)
Alternatively, you could extend your code like this
(->> data
(partition-by #(.startsWith % ":"))
(partition 2)
(map (fn [[[kw-str] strs]]
(cons (-> kw-str
(subs 1)
keyword)
strs))))
what about that:
(defn group-that [ arg ]
(if (not-empty arg)
(loop [list arg, acc [], result []]
(if (not-empty list)
(if (.startsWith (first list) ":")
(if (not-empty acc)
(recur (rest list) (vector (first list)) (conj result acc))
(recur (rest list) (vector (first list)) result))
(recur (rest list) (conj acc (first list)) result))
(conj result acc)
))))
Just 1x iteration over the Seq and without any need of macros.
Since the question is already here... This is my best effort:
(def data [":keyword0" "word0" "word1" ":keyword1" "word2" "word3"])
(->> data
(partition-by (fn [x] (.startsWith x ":")))
(partition 2)
(map (fn [[[k] w]] (apply conj [(keyword (subs k 1))] w))))
I'm still looking for a better solution or criticism of this one.
First, let's construct a function that breaks vector v into sub-vectors, the breaks occurring everywhere property pred holds.
(defn breakv-by [pred v]
(let [break-points (filter identity (map-indexed (fn [n x] (when (pred x) n)) v))
starts (cons 0 break-points)
finishes (concat break-points [(count v)])]
(mapv (partial subvec v) starts finishes)))
For our case, given
(def data [":keyword0" "word0" "word1" ":keyword1" "word2" "word3"])
then
(breakv-by #(= (first %) \:) data)
produces
[[] [":keyword0" "word0" "word1"] [":keyword1" "word2" "word3"]]
Notice that the initial sub-vector is different:
It has no element for which the predicate holds.
It can be of length zero.
All the others
start with their only element for which the predicate holds and
are at least of length 1.
So breakv-by behaves properly with data that
doesn't start with a breaking element or
has a succession of breaking elements.
For the purposes of the question, we need to muck about with what breakv-by produces somewhat:
(let [pieces (breakv-by #(= (first %) \:) data)]
(mapv
#(update-in % [0] (fn [s] (keyword (subs s 1))))
(rest pieces)))
;[[:keyword0 "word0" "word1"] [:keyword1 "word2" "word3"]]

idiomatic way to only update the first elem matching a pred in a coll

I have a seq, (def coll '([:a 20] [:b 30] [:c 50] [:d 90]))
I want to iterate through the seq, and modify only the first element that matches a predicate.
The predicate (def pred (fn [[a b]] (> b 30)))
(f pred (fn [[a b]] [a (+ b 2)]) coll) => ([:a 20] [:b 30] [:c 52] [:d 90])
f is the fn I want, which takes a pred, and a fn to apply to the first elem which matches the pred. All the rest of the elems are not modified and returned in the seq.
What is the idiomatic way to do the above?
One possible way is to split the collection with split-with, apply the function f to the first element of the second collection returned by split-with, and concat the elements together again.
(defn apply-to-first [pred f coll]
(let [[h t] (split-with (complement pred) coll)]
(concat h (list (f (first t))) (rest t))))
Note that the pred function in your example should probably look like this:
(def pred #(> (second %) 30))
As with most problems, there is a number of ways to solve it. This is but one of them.
If you're running Clojure 1.5, give this a try:
(reduce
(fn [acc [a b]]
(if (pred b)
(reduced (concat (:res acc) [[a (+ b 2)]] (rest (:coll acc))))
(assoc acc
:res (conj (:res acc) [a b])
:coll (rest (:coll acc)))))
{:coll coll :res []}
coll)
;; ([:a 20] [:b 30] [:c 52] [:d 90])
The key in this algorithm is the use of the reduced (note the 'd') function - it essentially tells reduce to halt the iteration and return the result. From its doc string:
-------------------------
clojure.core/reduced
([x])
Wraps x in a way such that a reduce will terminate with the value x
The code is a bit terse, but it should give you the basic idea.
Hope this helps.
This function is not hard to write recursively "from scratch". Not only is this a good learning exercise, it also produces the best solution: it is as lazy as possible, and does the absolute minimum amount of computation. So far, only one answer to this question is lazy, and that one calls pred twice on all the items before the update occurs: once in the take-while, and once in the drop-while, parts of split-with.
(defn update-first [pred f coll]
(lazy-seq
(when-let [coll (seq coll)]
(if (pred (first coll))
(cons (f (first coll))
(rest coll))
(cons (first coll)
(update-first pred f (rest coll)))))))
To keep it straightforward: find first element, find its index and use assoc to "update" the element at index:
(let [e (first (filter pred coll))
ind (.indexOf coll e)]
(assoc (vec coll) ind ((fn [[a b]] [a (+ b 2)]) e) ))
Dominic's note about pred applies:
(def pred #(> (second %) 30))