2012-02-02 49 views
9

在Clojure中,在兩個seqs上同時迭代並在兩個正在運行的元素上調用函數的最佳方法是什麼? 例如:clojure如何在兩個seqs的元素上一致地執行一個函數?

(def a (range 3)) 
(def b (range 100 103)) 
(defn my-func [] ...) ;some custom code 

代碼應執行我的-FUNC 3倍,像這樣:

(my-func 0 100) 
(my-func 1 101) 
(my-func 2 102) 

我怎樣才能做到這一點沒有定義任何功能或宏?

+1

(範圍100 102)只有兩個元素 - 也許你的意思是(範圍100 103)? – mikera 2012-02-03 02:51:46

+0

@mikera:謝謝。更新了問題 – viebel 2012-02-05 10:39:10

回答

15

map正是你所需要的,它需要一個函數和任意數量的seqs並按照你的意願調用它們。

(def a (range 3)) 
(def b (range 100 103)) 
user=> a 
(0 1 2) 
user=> b 
(100 101 102) 

user=> (defn my-func [a b] (str a ":" b)) 
#'user/my-func 

user=> (my-func 1 2) 
"1:2" 

user=> (map my-func a b) 
("0:100" "1:101" "2:102") 

因爲map是懶惰的,如果你想要的功能實際上現在運行:

(doall (map my-func a b)) 
+0

這不起作用。這輸出:(0:100 1:101 無零) – viebel 2012-02-02 23:53:30

+0

@viebel:你在REPL上運行並使用'println'嗎?如果是這樣,你的結果很混亂。假設你運行'(map#(println%1「:」%2)ab)',發生的事情是REPL打印了'(',然後'println'打印了'0:100'和'1:101'那麼REPL完成了打印地圖的結果,這是'無')。 – mange 2012-02-03 00:01:51

+0

nil nil是我在編輯它之前返回的prinln – 2012-02-03 00:02:01

3

您也可以嘗試

(doseq [[x y] (map list my-list1 my-list2)] 
    (println x y)) 

(map list list-2 list-2)創建一個列表,其中第一個元素是一個輸入列表的第一個元素的列表,第二個元素是第二個元素的列表,...

然後我們遍歷列表,使用Clojure的解構來提取原始列表的元素。

一般而言,如果您想要使用您正在應用的函數的返回值,您需要map。如果你只是執行一個副作用函數,我通常使用doseq。這種情況很複雜,因爲map並行工作,而doseq迭代了給定列表的Cartesian Product,所以您需要mapdoseq以獲得我們想要的行爲。

+0

是否有任何劑量類似的功能,並行迭代而不是笛卡爾產品。如果不是,它背後的理由是什麼? – viebel 2012-02-04 19:07:09

+0

據我所知,沒有這樣的功能。理想情況下doseq/for(它們共享相同的語法)將允許類似於:和option的選項允許兩個seq並行迭代。不幸的是,這樣的選擇不存在。 – Retief 2012-02-04 20:25:54

0

(doseq ... (map解決方案的選擇,如果你想成對迭代,而不是笛卡爾積,你也可以用interleave這樣的結合partition

> (def a (range 0 3)) 
> (def b (range 100 103)) 
> (interleave a b) 
(0 100 1 101 2 102) 
> (partition 2 (interleave a b)) 
((0 100) (1 101) (2 102)) 

partition調用提供對的(懶惰)起。

相關問題