2017-01-30 38 views
2

在做製作(映射f C1 C2)地圖(次數C1)次,即使C2具有更少的元素

(map f [0 1 2] [:0 :1]) 

f將被調用兩次,參數是

  • 0: 0
  • 1:1

是否有一個簡單而有效的方式,即不產生更多的中間序列等,使f得到第一個集合的每個值的調用,具有以下參數?

  • 0:0
  • 1:1
  • 2零

編輯通過@ fl00r在評論中解決問題。

觸發此問題的實際使用案例需要映射始終正常工作(count first-coll)次,無論第二個(或第三個或...)集合是否更長。

現在遊戲有點晚了,接受了答案後有點不公平,但如果一個好的答案被添加,只做我特別要求的 - 映射(count first-coll)次 - 我會接受。

+1

什麼應'(映射f [0 1] [0:1:2])'返回? – fl00r

回答

5

你可以這樣做:

(map f [0 1 2] (concat [:0 :1] (repeat nil))) 

基本上,墊第二科爾與尼爾斯的無限序列。 map到達第一個集合的末尾時停止。

的(渴望)環/易復發,可以引導結束的最長形式:

(loop [c1 [0 1 2] c2 [:0 :1] o []] 
    (if (or (seq c1) (seq c2))     
    (recur (rest c1) (rest c2) (conj o (f (first c1) (first c2)))) 
    o)) 

或者你可以寫地圖的懶惰版本,沒有類似的東西。

+0

喜歡這個'concat'方法 – fl00r

+0

@尤金 - beresovsky有沒有從這樣的回答缺了點什麼?我想提供一個答案,但我沒有看到任何未解決的問題。 – tar

0

只是爲了好玩

可以很容易地與普通Lisp的do宏來完成。我們可以用Clojure實現它,並用它做這個(以及更多好玩的東西):

(defmacro cl-do [clauses [end-check result] & body] 
    (let [clauses (map #(if (coll? %) % (list %)) clauses) 
     bindings (mapcat (juxt first second) clauses) 
     nexts (map #(nth % 2 (first %)) clauses)] 
    `(loop [[email protected]] 
     (if ~end-check 
     ~result 
     (do 
      [email protected] 
      (recur [email protected])))))) 

,然後只將其用於映射(注意它可以工作在超過2個colls):

(defn map-all [f & colls] 
    (cl-do ((colls colls (map next colls)) 
      (res [] (conj res (apply f (map first colls))))) 
     ((every? empty? colls) res))) 

在REPL:

user> (map-all vector [1 2 3] [:a :s] '[z x c v]) 
;;=> [[1 :a z] [2 :s x] [3 nil c] [nil nil v]] 
1

一般懶惰版本,如通過Alex Miller's answer建議,是

(defn map-all [f & colls] 
    (lazy-seq 
    (when-not (not-any? seq colls) 
     (cons 
     (apply f (map first colls)) 
     (apply map-all f (map rest colls)))))) 

例如,

(map-all vector [0 1 2] [:0 :1]) 
;([0 :0] [1 :1] [2 nil]) 

你可能會想專注map-all一個和兩個集合。

+0

我接受這個答案,因爲它易於使用,並且'map-all'不會創建任何中間序列,與'map'相比 - 可以添加一個,兩個和三個集合的arity重載,只是如'map'所做的那樣。 –

+0

@EugeneBeresovsky我發現寫作參考版本 - 清楚,但可能是緩慢的 - 的核心功能是真正瞭解他們的最佳途徑。這只是另一個例子。 – Thumbnail

+0

我會建議不要這樣做。此實現拋出一個#1:'(DOALL(地圖所有(8不停)(重複5000 8)(重複5000 8)))' – ClojureMostly

相關問題