2016-04-28 50 views
2

在這裏,我再次面對Clojure的一些問題。我有兩個向量向量。Clojure - 合併兩個向量不同大小的向量

[[a b c] [d e f] [g h i]] 

[[a b] [d e] [g h] [j k]] 

而且我想在某種程度上合併這兩個最終的載體將是這樣的:

[[a b c] [d e f] [g h i] [j k l]] 

在輸出中,最後一個項目[JKL ],當沒有合併值時(因爲它在第一個向量中沒有相應的項目),L是一個常量值。 我該怎麼做這樣的事情?

P.S .:我是Clojure的新手,我很欣賞精心製作的答案,以便我能更好地理解。另外,如果這是一個微不足道的問題,很抱歉。

+1

如果分量矢量不匹配,會發生什麼:'[[AB ]]'和'[[cde]]',說? – Thumbnail

回答

2

一般:

  • 把問題分解成可分離部分
  • 給東西的名字
  • 組成部分

因此,在這種情況下,你的問題可以細分爲:

  • 拆分列表int ○重疊和非重疊部分
  • 選擇最佳的各重疊部分
  • 填充所述非重疊部分爲正確的長度
  • 將它們組合到一起的。

所以,如果我做你的問題了幾個假設,這裏是打破下來,並建立它備份的例子:

user> (def a '[[a b c] [d e f] [g h i]]) 
#'user/a 
user> (def b '[[a b] [d e] [g h] [j k]]) 
#'user/b 

進行功能選擇正確的一對重疊部分。我選擇了長度雖然不過你想要的,你可以合併這些:

user> (defn longer-list [x y] 
     (if (> (count x) (count y)) 
      x 
      y)) 
#'user/longer-list 

作出墊的是太短了

user> (defn pad-list [l min-len default-value] 
     (into l (take (- min-len (count l)) (repeat default-value)))) 
#'user/pad-list 

讓使用這兩個功能進行分割再重組的功能列表的功能這個問題的部分:

user> (defn process-list [a b] 
     (let [a-len (count a) 
       b-len (count b) 
       longer-input (if (> a-len b-len) 
          a 
          b) 
       shorter-input (if (< a-len b-len) 
          a 
          b)] 
      (concat (map longer-list longer-input shorter-input) 
        (map #(pad-list % 3 'l) (drop (count shorter-input) longer-input))))) 
#'user/process-list 

,然後對其進行測試:-)

user> (process-list a b) 
([a b c] [d e f] [g h i] [j k l]) 

還有更多的細節需要解決,比如當列表的列表長度相同時,以及它們不是彼此的子集時會發生什麼。(是的,你可以粉碎,這歸因於「一個班輪」太)

+0

謝謝你,解釋是完美的:)。 – greenFedoraHat

0

我想看看clojure.core.matrix(見here);它有一些很好的操作,可以幫助你做到這一點。

0

我一般會去用以下方法:

  1. 填充集合到最長的一個
  2. 地圖的尺寸​​都,將集合中的每個項目填充到最長的映射項目的大小以選擇結果值。

這是更好的代碼來說明吧:

首先,讓我們做了一些輔助功能:

(defn max-count [coll1 coll2] (max (count coll1) (count coll2))) 

它的名字說自明。

(defn fill-up-to [coll size] (take size (concat coll (repeat nil)))) 

這一個填滿了nil S中收集了一些大小:

user> (fill-up-to [1 2 3] 10) 
(1 2 3 nil nil nil nil nil nil nil) 

現在合併功能:

(defn merge-colls [v1 v2 default-val] 
    (let [coll-len (max-count v1 v2) 
     comp-len (max-count (first v1) (first v2))] 
    (mapv (fn [comp1 comp2] 
      (mapv #(or %1 %2 default-val) 
        (fill-up-to comp1 comp-len) 
        (fill-up-to comp2 comp-len))) 
      (fill-up-to v1 coll-len) 
      (fill-up-to v2 coll-len)))) 

mapv工作從充滿初始參數進行的募款最長的一個長度(coll-len),所以在問題的背景下,它將是:

(mapv some-fn [[a b c] [d e f] [g h i] nil]] 
       [[a b] [d e] [g h] [j k]]) 

內mapv在內矢量操作,(在這種情況下3)填充到comp-len

(mapv #(or %1 %2 default-val) '[a b c] '[d e nil]) 
... 
(mapv #(or %1 %2 default-val) '[nil nil nil] '[j k nil]) 

讓我們來測試一下:

user> (let [v1 '[[a b c] [d e f] [g h i]] 
      v2 '[[a b] [d e] [g h] [j k]]] 
     (merge-colls v1 v2 'l)) 
[[a b c] [d e f] [g h i] [j k l]] 

確定它的工作原理就像我們要。

現在如果你看一下merge-colls,您可能會注意到圖形的重複:

(mapv some-fn (fill-up-to coll1 size) 
       (fill-up-to coll2 size)) 

我們可以搬進搬出這個模式功能消除重複:

(defn mapv-equalizing [map-fn size coll1 coll2] 
    (mapv map-fn (fill-up-to coll1 size) (fill-up-to coll2 size))) 

和重寫我們的合併:

(defn merge-colls [v1 v2 default-val] 
    (let [coll-len (max-count v1 v2) 
     comp-len (max-count (first v1) (first v2))] 
    (mapv-equalizing (fn [comp1 comp2] 
         (mapv-equalizing #(or %1 %2 default-val) 
             comp-len comp1 comp2)) 
        coll-len v1 v2))) 

測試:

user> (let [v1 '[[a b c] [d e f] [g h i]] 
      v2 '[[a b] [d e] [g h] [j k]]] 
     (merge-colls v1 v2 'l)) 
[[a b c] [d e f] [g h i] [j k l]] 

好的。現在我們可以通過刪除集合大小綁定縮短,因爲我們需要這些值只有一次:

在REPL
(defn merge-colls [v1 v2 default-val] 
    (mapv-equalizing 
    (partial mapv-equalizing 
      #(or %1 %2 default-val) 
      (max-count (first v1) (first v2))) 
    (max-count v1 v2) v1 v2)) 

user> (let [v1 '[[a b c] [d e f] [g h i]] 
      v2 '[[a b] [d e] [g h] [j k]]] 
     (merge-colls v1 v2 'l)) 
[[a b c] [d e f] [g h i] [j k l]]