2016-04-28 117 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]]