I'm a really newbie at clojure.
I have this
(defn max-val [x & xs]
(reduce #(if (< %1 %2) %2 %1) (flatten (cons x xs))))
Which are the %1 and %2 arguments?
I understand that
(flatten (cons 1 2 3)
Will return a lazy-seq, making just one argument to the #() function
Let's look at the docs for reduce
(reduce f coll) (reduce f val coll)
f should be a function of 2 arguments. If val is not supplied,
returns the result of applying f to the first 2 items in coll, then
applying f to that result and the 3rd item, etc. If coll contains no
items, f must accept no arguments as well, and reduce returns the
result of calling f with no arguments. If coll has only 1 item, it
is returned and f is not called. If val is supplied, returns the
result of applying f to val and the first item in coll, then
applying f to that result and the 2nd item, etc. If coll contains no
items, returns val and f is not called.
So it applies the function to the next item in the list, as well as the result of the previous invocation (the first time using the first two items in the list).
Imagine you call your function like this:
(reduce #(if (< %1 %2) %2 %1) '(1 2 3 4))
It will first be called with 1 and 2, returning 2. Then it will be called with the result, 2, and the next item, 3, and return 3. Then it's called with the result, 3, and the next item 4, and returns 4 as the final result.
Each step uses the result of the previous invocation as the first argument for the next time.
Related
I want to write a function which simply updates a vector in a map with new value, but can take any number of args, but at least one.
Here is example:
(defn my-update [what item & items]
(update what :desired-key conj item items))
Unfortunately, this doesn't work. Despite that update do have a signature with multiple values (like [m k f x y]), all remaining arguments to my-update will be joined into one sequence, which will be passed to conj as one argument.
Instead, wrapping conj with apply in an anonymous function does work, but looks not so elegant:
(defn my-update [what item & items]
(update what :desired-key #(apply conj % item items))
What is the idiomatic way of writing such a function like my-update?
You can simply insert apply before update. That will call the function update with the arguments that follows except for the last argument which should be a sequence, whose elements become the remaining arguments in the call:
(defn my-update [what item & items]
(apply update what :desired-key conj item items))
(my-update {:desired-key [0]} 1 2 3 4)
;; => {:desired-key [0 1 2 3 4]}
(my-update {:desired-key [0]})
;; Exception: Wrong number of args (1) passed to: my-update
This way, you can keep the function argument list [what item & items] that makes it clear that at least one item needs to be provided.
In general, a call (apply f a b c ... [x y z ...]) will evaluate to the same as (f a b c ... x y z ...).
Your existing solution isn't so bad. One small improvement is to use the into function, which uses conj internally to join two sequences together:
(defn my-update [what & items]
(update what :a into items))
with result
(my-update {:a [1]} 2 3 4) => {:a [1 2 3 4]}
Another alternative is to extract out the anonymous function into a named function:
(defn append-to-seq
[seq item items]
(-> (vec seq) ; ensure it is a vector so conj adds to the end, not beginning
(conj item)
(into items)))
(defn my-update [what item & items]
(update what :a append-to-seq item items))
I am trying to understand this function from clojuredocs.org:
;; Create a word frequency map out of a large string s.
;; `s` is a long string containing a lot of words :)
(reduce #(assoc %1 %2 (inc (%1 %2 0)))
{}
(re-seq #"\w+" s))
; (This can also be done using the `frequencies` function.)
I dont understand this part: (inc (%1 %2 0))
The first argument (%1 in the anonymous function) to the function passed to reduce is the accumulator, which is initally the empty map {} passed as the second argument to reduce. Maps are functions which lookup the value for the given key, returning the optional default if the key is not found e.g.
({"word" 1} "word") = 1
and
({"word" 1} "other" 0) = 0
so
(%1 %2 0)
looks up the count for the current word (second argument to the reducing function) in the accumulator map, returning 0 if the word has not been added yet. inc increments the current count, so
#(assoc %1 %2 (inc (%1 %2 0))
increments the count of the current word in the intermediate map, or sets it to 1 if this is the first time the word has been encountered.
Here's an easier to read example of the same thing, not using anonymous function syntax:
(reduce
(fn [acc elem]
(assoc acc elem (inc (acc elem 0))))
{}
(re-seq #"\w+" "a dog a cat a dog a banana"))
=> {"a" 4, "dog" 2, "cat" 1, "banana" 1}
Here acc is the map we are building up, and elem is the current word. Let's break down (inc (acc elem 0)):
inc is going to increment the number returned from the inner expression
(acc elem 0) is going to get the current number from the acc map for the word elem, and if there is no number there it'll return 0. This is short for (get acc elem 0) -- maps are functions too and behave like the get function.
You can also achieve the same effect as (assoc acc elem (inc (acc elem 0))) with (update acc elem (fnil inc 0)).
The same logic applies when you replace the reduce function with an anonymous syntax using numbered arguments.
The code you are asking about is essentially that of the standard frequencies function with transients removed:
(defn frequencies [coll]
(reduce
(fn [counts x] (assoc counts x (inc (get counts x 0))))
{}
coll))
This
uses a fn form instead of an anonymous function literal (as does
Taylor Wood above) and
includes a superfluous get, which gives us a clue to the default
0 value.
I have this function:
(defn ! [x]
(let [n x product 1]
(if (zero? n)
product
(recur (- n 1) (* product n)))))
and I got error: java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2 (NO_SOURCE_FILE:33)
but this factorial from other SO question work fine. Why?
(defn fact [x]
(loop [n x f 1]
(if (= n 1)
f
(recur (dec n) (* f n)))))
You can't recur on let.
When you recur here, you are actually recurring on the function definition which has one argument hence java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2 (NO_SOURCE_FILE:33).
On the second example (s)he's using loop which you should use when you want to recur on some other arguments, other than the functions.
in your example recur loops to ! which is expecting 1 param but gets 2,
in the second example recur loops to loop which is expecting 2 params and gets 2 params
I made this function to remove consecutive duplicates, but I wanted to know if there was a better or shorter way to express it using distinct or something like that.
(defn duplicates
[s]
(reduce
#(if-not (= (last %1) %2)
(conj %1 %2) %1)
[] s))
clojure-1.7.0-alpha1 has a correct version of this function under the name dedupe.
The one you quoted returns its input sequence without consecutive duplicates. (Almost certainly) unwittingly, it also swallows all successive nil values if they begin the input sequence.
#(if-not (= (last %1) %2)
(conj %1 %2)
%1)
The lambda to reduce says: If the last element of the accumulator (%1) is unequal to the next input element (%2), add it to the accumulator, otherwise return the accumulator.
Because (last []) evaluates to nil it will never add nil values while the accumulator is empty. I leave fixing that as an exercise to the reader:
Make sure that duplicates returns the expected result [nil true nil] for input [nil nil true true nil].
Note: When operating with a vector, using peek performs significantly better than last.
EDIT (Since you edited your question): distinct returns each value of the input sequence only once. Unlike set it returns lazy-sequence.
A more idiomatic way to write duplicates/dedupe is the one that A. Webb posted as a comment (since it is also lazy). Otherwise, fixing the lambda to work correctly with an empty accumulator as its input and using peek instead of last would be more idiomatic.
Instead of fixing the lambda, in clojure-1.7.0-alpha1 you would use the dedupe transducer for eager evaluation, e. g.:
(into [] (dedupe) [nil nil true true nil])
-> [nil true nil]
Or for lazy evaluation:
(dedupe [nil nil true true nil])
-> (nil true nil)
The anonymous function inside the reduce conjs an element to a sequence if it's different from the last element. You could rewrite it like this:
(defn maybe-conj [s e]
(if (= (last s) e)
s
(conj s e)))
Then you could rewrite compress-sequence as:
(defn compress-sequence [s]
(reduce maybe-conj [] s))
What this will do is go through each element of a sequence, and append it to the initial empty vector only if it's different from the last currently in that vector. The output will be a vector of the initial sequence with any runs removed. Example:
(compress-sequence [1 1 1 1 1 2 3 4 5 5 5 5 6 6 6 5 6 6 7 8 9])
evaluates to
[1 2 3 4 5 6 5 6 7 8 9]
I've tried to find the answer but it's quite difficult to search just the %-mark. So I've seen %-mark sometimes but I can't understand what is its function. It would be very nice if somebody could tell the explanation.
I'm assuming this is inside an anonymous function, like #(first %) if so it means the first parameter. If there are more that one, you can number them %1,%2 etc.
So for instance
(filter #(odd? %) [1 2 3 4 5 6]) => (1 3 5)
Note: In this example you would normally just do (filter odd? [1 2 3 4 5 6])
#(blah %) is shorthand for an argument to an anonymous function. So if you're squaring each element in a list, instead of
(map (fn [x] (* x x)) [1 2 3])
you can write
(map #(* % %) [1 2 3])
i.e. substituting #(* % %) for (fn [x] (* x x)) as the anonymous function. Each will give (1 4 9)
% is just a placeholder for arguments in the #(...) reader macro witch rewrites to a (fn* ...) call. It means the first passed argument.
You can add a number after the % to indicate index number of argument, beware first argument index is 1, so % == %1.
You shall provide as many arguments to the returned function as the highest index you use in the function definition.
#(str %4 %2)
gives
(fn* [p1__680# p2__679# p3__681# p4__678#] (str p4__678# p2__679#))
and needs 4 arguments.
Observe that %4 and %2 are managed first and in reading order and non used arguments are created after by the macro filling the gaps.