mapcat使用地图和concat

时间:2012-11-05 01:11:31

标签: map clojure concat reduce

为了更好地理解 mapcat ,我举了一个例子:

user>  (mapcat #(list % %) [1 2 3])
(1 1 2 2 3 3)

并试图重现文档所描述的用途, map concat

user> (doc mapcat)
clojure.core/mapcat
([f & colls])
  Returns the result of applying concat to the result of applying map
  to f and colls.  Thus function f should return a collection.

通过这样做:

user>  (concat (map #(list % %) [1 2 3]))
((1 1) (2 2) (3 3))

然而,你可以看到它不起作用。但是我可以像这样使用reduce,但不知道它是否正确:

user>  (reduce #(concat %1 %2) (map #(vec (list % %)) [1 2 3]))
(1 1 2 2 3 3)

以上是有效的,但我不知道是否使用 map concat 重新创建 mapcat 的功能。

基本上我想了解 mapcat 的工作原理。

发生了什么以及如何访问 mapcat 的来源? (我正在使用Emacs + nrepl)

2 个答案:

答案 0 :(得分:6)

user=> (source mapcat)
(defn mapcat
  "Returns the result of applying concat to the result of applying map
  to f and colls.  Thus function f should return a collection."
  {:added "1.0"}
  [f & colls]
    (apply concat (apply map f colls)))
nil
user=> 

reduce也有效的原因是因为它有效:

(concat (concat '(1 1) '(2 2)) '(3 3))
源代码中使用的

apply扩展为:

(concat '(1 1) '(2 2) '(3 3))

使用concat初次尝试:

  user=> (map #(list % %) [1 2 3])
  ((1 1) (2 2) (3 3))
  user=> (concat (list '(1 1) '(2 2) '(3 3)))
  ((1 1) (2 2) (3 3))
  user=> (concat [1])
  (1)

您可以看到,如果使用单个参数调用concat,则会返回该参数。

答案 1 :(得分:2)

concat是一个可变函数,即它可以采用n个参数,其中每个参数是一个值序列,即签名变为(defn concat [& lst]])。在您的示例中,您使用单个参数调用concat,假设concat采用seq的seq值进行连接,这就是为什么您得到结果,即返回相同的列表列表。

(apply concat(apply map #(list % %) [1 2]))不会工作。

(apply map #(list % %) [[1 2]])(apply map #(list % %) [1 2] [])将有效。

这是因为apply要求最后一个参数是一个值序列,并且该值序列中的每个项目都将作为参数传递给应用函数。在您申请失败的情况下,呼叫将扩展为(map #(list % %) 1 2)这是错误的,并且错误消息还显示它无法将长转换为序列,因为地图需要序列作为参数。