问题
Can someone please explain how the below anonymous function is evaluated?
(defn min-by [f coll]
(when (seq coll)
(reduce (fn [min this]
(if (> (f min) (f this)) this min))
coll)))
(min-by :cost [{:cost 100} {:cost 36} {:cost 9}])
;=> {:cost 9}
I don't understand where the arguments min
and this
come from. It seems like coll is being implicitly destructured perhaps.
How can I better understand what this function is doing?
回答1:
Reduce expects a function as it's first argument. This function takes two arguments where the first argument is "the result thus far" and the second argument is "the data with which to change it". In the above example reduce is taking a function that recieves the smallest thing found thus far, and the next element to compare it to. It then decides which of them is smaller and keeps it as the result thus far.
(defn min-by [f ;; this if a function that will be passed the smallest value
;; yet found and called again with the current value.
;; the result of these two calls will decide which is the min.
coll]
(when (seq coll)
(reduce
;; first arg to reduce: a function to add something to the result
;; this function will be called once for each of the elements in the
;; collection passed as the second argument
(fn [min ; the result thus far
this] ; the next element to include in the result
;; here we decide which is smaller by passing each to the function f
;; that was passed to min-by and compare is results for each of them.
(if (> (f min) (f this)) this min))
;; second arg to reduce: the collection to work on
;; each element in this collection will be one of the values of
;; the "this" argument to the function above
coll)))
There is also an optional argument in the middle of these two that specifies the initial value for the result. If you omit this optional argument, as in the example above, then the first two arguments are used to generate the first value in the result. So the reducing function is actually called one less time than the number of elements in the input collection.
user> (defn print+ [& numbers] (println "called print+") (apply + numbers))
#'builder.upload/print+
user> (reduce print+ [1 2 3])
called print+
called print+
6
user> (reduce print+ 0 [1 2 3])
called print+
called print+
called print+
6
来源:https://stackoverflow.com/questions/25026159/reduce-in-clojure