2012-11-05 60 views
7

爲了更好地理解會員名:mapcat我花了一個例子:會員名:mapcat使用地圖和CONCAT

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

並試圖重現什麼文檔描述了使用上的目的,地圖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)) 

但是,正如你所看到的,它不起作用。不過,我可以用減少這樣的,但不知道這是否是正確的:

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

上述作品,但我不知道這是否是重新建立一個正確的方式,使用地圖CONCAT什麼mapcat呢。

基本上我想了解mapcat在引擎蓋下工作。

這是怎麼回事,我怎樣才能訪問mapcat的來源? (我使用Emacs + nrepl)

+1

使用'apply'可能比'reduce'更好,因爲'reduce'會爲每對參數做'concat'。由於'concat'是懶惰的,當這些值實際上被強制的時候,你最終會得到一個_really_深度調用堆棧,可能會導致堆棧溢出。 [這是一個簡單的例子。](https://www.refheap.com/paste/6409) – DaoWen

+2

只是一個提示 - 在使用'reduce'實現時,不需要將'concat'包裝在匿名函數中。這也可以工作:'(reduce concat(map ...))'並且更好,因爲它更好地處理空輸入的情況。 – Alex

回答

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

(應用concat(應用map f colls))看起來很奇怪。我無法讓它工作。 *(應用concat(map f colls))*對我有效,但我不明白* apply *的雙重用法。例如*(apply concat(apply map#(list%%)[1 2]))*不起作用!? –

+0

Apply想要一個參數列表,所以只有1個參數的例子纔是正確的fortm(應用地圖#(列表%%)[[1 2]])) – mikkom

2

concat是一個可變參數函數,即它可以取n個參數,其中每個參數是一個值序列,即簽名變成(defn concat [& lst]])。而在你的例子中,你用一個參數調用concat,假設concat將一個seq的值串聯起來,這就是爲什麼你得到結果,即返回的列表是相同的列表。

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

(apply map #(list % %) [[1 2]])(apply map #(list % %) [1 2] [])將工作。

這是因爲apply會期望最後一個參數是一個值序列,並且該值序列中的每個項目都將作爲參數傳遞給應用函數。在你申請失敗的情況下,調用將擴展到(map #(list % %) 1 2)這是錯誤的,並且錯誤消息還顯示它不能將長序列轉換爲序列作爲映射需要序列作爲參數。