[英]Clojure - Merge two vectors of vectors different sizes
在這里,我再次面臨 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在沒有要合並的值時是一個常數值(因為它在第一個向量中沒有對應的項。我該怎么做?
PS:我是 Clojure 的新手,我很欣賞詳細的答案,以便我能更好地理解。 另外,對不起,如果這是一個微不足道的問題。
一般來說:
因此,在這種情況下,您的問題可以分解為:
因此,如果我對您的問題做出幾個假設,這里有一個分解並重新構建它的示例:
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])
還有更多的細節需要解決,比如當列表的列表長度相同時會發生什么,如果它們不是彼此的子集。 (是的,您也可以將其粉碎為“單襯”)
我會看看clojure.core.matrix
(見這里); 它有一些很好的操作可以幫助你解決這個問題。
我通常會采用以下方法:
最好用代碼來說明:
首先讓我們組成一些輔助函數:
(defn max-count [coll1 coll2] (max (count coll1) (count coll2)))
它的名字不言而喻。
(defn fill-up-to [coll size] (take size (concat coll (repeat nil))))
這個用nil
填充集合到一定大小:
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 對內部向量進行操作,填充到comp-len
(在這種情況下為 3):
(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]]
好的。 現在我們可以通過刪除集合大小綁定來縮短它,因為我們只需要一次這些值:
(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]]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.