Essentially, I want a function that works like this:
user=> (pos 'c '(a b c d e f g) =)
2
user=> (pos 'z '(a b c d e f g) =)
nil
And I came up with this:
(defn pos
"Gets position of first object in a sequence that satisfies match"
[object sequence match]
(loop [aseq sequence position 0]
(cond (match object (first aseq)) position
(empty? aseq) nil
:else (recur (rest aseq) (inc position)))))
So my question is, is there some built-in function that would allow us to do this, or would there be a better, more functional/Clojure-ish way to write the pos function?
Well, if you really want to look for a particular item you can use .indexOf on the collection; if you're looking to do something more general with predicates you don't need a function and an item, just a function is plenty.
(defn pos [pred coll]
(->> coll
(map-indexed #(when (pred %2) %1))
(remove nil?)
(first)))
user> (pos #{'c} '(a b c d e f g))
2
On the other hand, there's a reason this isn't included in clojure.core: it's not very efficient, and you very rarely care about indices in a collection - if you do, you should usually rethink your algorithm.
Related
So I am trying to solve this problem, and this is the code I have come up with:
First I have a pack function, receives a list and groups same elements into a vector.
(defn pack [lst]
(def a [])
(def vect [])
(cond
(empty? lst)
lst
:else
(loop [i 0]
(def r (get lst i))
(def t (get lst (+ i 1)))
(if (= r t)
(def vect (conj vect r))
)
(if (not= r t)
(and (def vect (conj vect r)) (and (def a (conj a vect)) (def vect [])))
)
(if (= i (- (count lst) 1))
a
(recur (inc i))
)
))
)
for example if I have this vector:
(def tes '[a a a a b c c a a d e e e e])
pack function will return this:
[[a a a a] [b] [c c] [a a] [d] [e e e e]]
Then I tried doing the "encode" part of the problem with this code:
(def v1 [])
(def v2 [])
(conj v2 (conj v1 (count (get (pack tes) 0)) (get (get (pack tes) 0) 0)))
And it returned what I wanted, a vector "v2" with a vector "v1" that has the "encoded" item.
[[4 a]]
So now I try to make the function:
(defn encode [lst]
(loop [index 0 limit (count (pack lst)) v1 [] v2[]]
(if (= index limit)
lst
(conj v2 (conj v1 (count (get (pack tes) index)) (get (get (pack tes) index) index)))
)
(recur (inc index) limit v1 v2)
)
)
(encode tes)
but I get this error:
2021/03/07 00:00:21 got exception from server /usr/local/bin/lein: line 152:
28 Killed "$LEIN_JAVA_CMD" "${BOOTCLASSPATH[#]}" -Dfile.encoding=UTF-8 -Dmaven.wagon.http.ssl.easy=false -Dmaven.wagon.rto=10000 $LEIN_JVM_OPTS
-Dleiningen.original.pwd="$ORIGINAL_PWD" -Dleiningen.script="$0" -classpath "$CLASSPATH" clojure.main -m leiningen.core.main "$#"
2021/03/07 01:42:20 error reading from server EOF
Any way to fix my code or to solve the problem more efficiently but still return a vector?
juxt can be used in the pack function:
(defn pack [xs]
(map (juxt count first) (partition-by identity xs)))
(defn unpack [xs]
(mapcat #(apply repeat %) xs))
Don't use def inside function, because it creates global
variable. Use let instead.
Don't use multiple if in row, there is cond.
Format your code better- for example, put all parentheses on the end together on one line.
Here is more efficient solution:
(defn pack [lst]
(letfn [(pack-help [lst]
(if (empty? lst) '()
(let [elem (first lst)]
(cons (vec (take-while #(= % elem) lst))
(pack-help (drop-while #(= % elem) lst))))))]
(vec (pack-help lst))))
(defn pack-with-count [lst]
(mapv #(vector (count %) (first %))
(pack lst)))
(defn unpack [packed-lst]
(into [] (apply concat packed-lst)))
(pack '[a a a a b c c a a d e e e e])
(pack-with-count '[a a a a b c c a a d e e e e])
(unpack '[[a a a a] [b] [c c] [a a] [d] [e e e e]])
As a rule, whenever you reach for loop/recur, there are some pieces of the standard library which will allow you to get the desired effect using higher-order functions. You avoid needing to implement the wiring and can just concentrate on your intent.
(def tes '[a a a a b c c a a d e e e e])
(partition-by identity tes)
; => ((a a a a) (b) (c c) (a a) (d) (e e e e))
(map (juxt count first) *1)
; => ([4 a] [1 b] [2 c] [2 a] [1 d] [4 e])
(mapcat #(apply repeat %) *1)
; => (a a a a b c c a a d e e e e)
Here *1 is just the REPL shorthand for "previous result" - if you need to compose these into functions, this will be replaced with your argument.
If you really need vectors rather than sequences for the outer collection at each stage, you can wrap with vec (to convert the lazy sequence to a vector), or use mapv instead of map.
Finally - the error message you are getting from lein is a syntax error rather than a logic or code problem. Clojure generally flags an unexpected EOF if there aren't enough closing parens.
(println "because we left them open like this -"
Consider working inside a REPL within an IDE, or if that isn't possible then using a text editor that matches parens for you.
I am currently reading the book "The Joy of Clojure", 2nd edition.
In Chapter 7 "Functional Programming", I came across the following function that was used to describe function composition.
(defn fnth [n]
(apply comp
(cons first
(take (dec n) (repeat rest)))))
((fnth 5) '[a b c d e])
;=> e
I don't fully understand the mechanics of that function.
Trying to reproduce the inner scope without using comp, the function produces a repeating list:
(take (dec 5) (repeat (rest '[a b c d e])))
;=> ((b c d e) (b c d e) (b c d e) (b c d e))
What is the point of attaching first to that repeating list by using comp?
Is this also the last part of the function list which is fed into comp?
(first (take (dec 5) (repeat (rest '[a b c d e]))))
=> (b c d e)
Thank you in advance!
The fnth function works by constructing a sequence of the form (first rest rest ... rest) i.e. first followed by n - 1 rests. It then composes them into a single function by applying comp. For (fnth 5) this is
(apply comp (first rest rest rest rest))
When the result function is called on the vector [a b c d e] the resulting application is
(first (rest (rest (rest (rest [a b c d e])))))
i.e. the first element of the 4th tail of the input sequence.
Your attempted reconstruction only calls rest once and then reapeats the returned sequence instead.
This fnth does not (itself) return the nth item of a collection, but rather produces a function that does so.
What function should it produce to get the 1st item?
(defn nth-1 [coll]
(first coll))
What function should it produce to get the 2nd item?
(defn nth-2 [coll]
(first (rest coll)))
What function should it produce to get the 3rd item?
(defn nth-3 [coll]
(first (rest (rest coll))))
So there's a pattern! But the nesting would be a challenge for fnth.
An equivalent formulation for (first (rest (rest x))) is ((comp first rest rest) x). Now we can write nth-3 as
(defn nth-3 [coll]
((comp first rest rest) coll))
With this approach fnth is easier to write. But it would be easier still if we rewrote (comp first rest rest) as (apply comp [first rest rest]). There! Now fnth needs is to make a list of first + the right number of rest's, and apply comp to that list.
I'm looking for something that is probably very well defined in Clojure (in the Lisp world at large in fact) but I don't have enough experience or culture to get on the right track and Google hasn't been very helpful so far.
Let's say I have three simple forms:
(defn add-one [v] (+ v 1))
(defn add-two [v] (+ v 2))
(defn add-three [v] (+ v 3))
Out of convenience, they are stored in a vector. In the real world, that vector would vary depending on the context:
(def operations
[add-one
add-two
add-three])
And I also have an initial value:
(def value 42)
Now, I would like to apply all the functions in that vector to that value and get the result of the combined operations:
(loop [ops operations
val value]
(if (empty? ops)
val
(recur (rest ops)
((first ops) val))))
While this does work, I'm surprised there isn't a higher level form just for that. I've looked all over the place but couldn't find anything.
The functional phrase you are searching for is (apply comp operations):
((apply comp operations) 42)
;48
Your loop does work if you feed it 42 for value:
(loop [ops operations
val 42]
(if (empty? ops)
val
(recur (rest ops)
((first ops) val))))
;48
This applies the operations in the opposite order from comp.
... As does using reduce:
(reduce (fn [v f] (f v)) 42 operations)
;48
If you look at the source code for comp, you'll find that the general case essentially executes a loop similar to yours upon a reversed list of the supplied functions.
'In Lisp world at large' you can use reduce:
user> (reduce (fn [x y] (y x)) 5 [inc inc inc inc])
;; => 9
This may look not so sexy, but it works everywhere with minor variations (this is Common Lisp, for example):
CL-USER> (reduce (lambda (x y) (funcall y x))
'(1+ 1+ 1+ 1+)
:initial-value 5)
9
In clojure, this is valid:
(loop [a 5]
(if (= a 0)
"done"
(recur (dec a))))
However, this is not:
(let [a 5]
(if (= a 0)
"done"
(recur (dec a))))
So I'm wondering: why are loop and let separated, given the fact they both (at least conceptually) introduce lexical bindings? That is, why is loop a recur target while let is not?
EDIT: originally wrote "loop target" which I noticed is incorrect.
Consider the following example:
(defn pascal-step [v n]
(if (pos? n)
(let [l (concat v [0])
r (cons 0 v)]
(recur (map + l r) (dec n)))
v))
This function calculates n+mth line of pascal triangle by given mth line.
Now, imagine, that let is a recur target. In this case I won't be able to recursively call the pascal-step function itself from let binding using recur operator.
Now let's make this example a little bit more complex:
(defn pascal-line [n]
(loop [v [1]
i n]
(if (pos? i)
(let [l (concat v [0])
r (cons 0 v)]
(recur (map + l r) (dec i)))
v)))
Now we're calculating nth line of a pascal triangle. As you can see, I need both loop and let here.
This example is quite simple, so you may suggest removing let binding by using (concat v [0]) and (cons 0 v) directly, but I'm just showing you the concept. There may be a more complex examples where let inside a loop is unavoidable.
I've been working through problems on 4Clojure today, and I ran into trouble on Problem 28, implementing flatten.
There are a couple of definite problems with my code.
(fn [coll]
((fn flt [coll res]
(if (empty? coll)
res
(if (seq? (first coll))
(flt (into (first coll) (rest coll)) res)
(flt (rest coll) (cons (first coll) res))))) coll (empty coll)))
I could use some pointers on how to think about a couple of problems.
How do I make sure I'm not changing the order of the resulting list? cons and conj both add elements wherever it is most efficient to add elements (at the beginning for lists, at the end for vectors, etc), so I don't see how I'm supposed to have any control over this when working with a generic sequence.
How do I handle nested sequences of different types? For instance, an input of '(1 2 [3 4]) will will output ([3 4] 2 1), while an input of [1 2 '(3 4)] will output (4 3 2 1)
Am I even approaching this from the 'right' angle? Should I use a recursive inner function with an accumulator to do this, or am I missing something obvious?
You should try to use HOF (higher order functions) as much as possible: it communicates your intent more clearly and it spares you from introducing subtle low-level bugs.
(defn flatten [coll]
(if (sequential? coll)
(mapcat flatten coll)
(list coll)))
Regarding your questions about lists and vectors. As you might see in tests, output is list. Just make correct abstraction. Fortunately, clojure already has one, called sequence.
All you need is first, rest and some recursive solution.
One possible approach:
(defn flatten [[f & r]]
(if (nil? f)
'()
(if (sequential? f)
(concat (flatten f) (flatten r))
(cons f (flatten r)))))
Here's how to do it in a tail call optimised way, within a single iteration, and using the least amount of Clojure.core code as I could:
#(loop [s % o [] r % l 0]
(cond
(and (empty? s) (= 0 l))
o
(empty? s)
(recur r
o
r
(dec l))
(sequential? (first s))
(recur (first s)
o
(if (= 0 l)
(rest s)
r)
(inc l))
:else
(recur (rest s)
(conj o (first s))
r
l)))