Clojure归约函数

Clojure归约函数,clojure,Clojure,我试图从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 `frequenc

我试图从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.)
我不理解这部分:(inc(%1%2 0))

传递给
reduce
的函数的第一个参数(
%1
)是累加器,它最初是作为第二个参数传递给
reduce
的空映射。映射是查找给定键的值的函数,如果找不到键,则返回可选的默认值,例如

({"word" 1} "word") = 1

所以

在累加器映射中查找当前单词(reduce函数的第二个参数)的计数,如果尚未添加单词,则返回0
inc
增加当前计数,因此

#(assoc %1 %2 (inc (%1 %2 0))

增加中间映射中当前单词的计数,如果这是第一次遇到该单词,则将其设置为1。

下面是一个简单易懂的示例,不使用匿名函数语法:

(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}
这里的
acc
是我们正在构建的地图,
elem
是当前的单词。让我们分解一下
(inc(acc elem 0))

  • inc
    将递增从内部表达式返回的数字
  • (acc elem 0)
    将从
    acc
    地图中获取
    elem
    单词的当前编号,如果没有编号,则返回
    0
    。这是
    (get acc elem 0)
    ——映射也是函数,其行为类似于
    get
    函数
  • 您还可以使用
    (更新acc elem(fnil inc 0))
    实现与
    (assoc acc elem(inc(acc elem 0))相同的效果


    当您使用使用编号参数的匿名语法替换reduce函数时,同样的逻辑也适用。

    您询问的代码基本上是删除的:

    这个

    • 使用
      fn
      表单而不是 )及
    • 包括一个多余的,这给了我们一个默认的线索
      0
    #(assoc %1 %2 (inc (%1 %2 0))
    
    (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}
    
    (defn frequencies [coll]
       (reduce
         (fn [counts x] (assoc counts x (inc (get counts x 0))))
         {}
         coll))