Clojure - 合并两个向量不同大小的向量

时间:2016-04-28 16:18:22

标签: vector clojure functional-programming

在这里,我再次面临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]]

在输出中,最后一项[j k l],当没有要合并的值时,L是一个常数值(因为它在第一个向量中没有对应的项目。 我该怎么办呢?

P.S。:我是Clojure的新手,我很欣赏一个精心设计的答案,以便我能更好地理解。另外,对不起,如果这是一个微不足道的问题。

3 个答案:

答案 0 :(得分:2)

一般来说:

  • 将问题分解为可分离的部分
  • 给出名字
  • 撰写部分

因此,在这种情况下,您的问题可以分解为:

  • 将列表拆分为重叠和不重叠的部分
  • 选择每个重叠部分的最佳部分
  • 将非重叠部分填充到正确的长度
  • 将它们组合在一起。

因此,如果我对您的问题做出一些假设,那就是将其分解并重新构建它的示例:

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]) 

还有更多细节需要解决,比如当列表列表长度相同时,以及它们不是彼此的子集时会发生什么。 (是的,你可以把它粉碎到一个&#34;一个班轮&#34;也是)

答案 1 :(得分:0)

我会看一下clojure.core.matrix(见here);它有一些很好的操作,可以帮助你。

答案 2 :(得分:0)

我通常采用以下方法:

  1. 将收藏品填充到最长的收藏品
  2. 映射它们,将集合中的每个项目填充到最长的映射项目的大小,以选择结果值。
  3. 最好用代码来说明它:

    首先让我们组成一些辅助函数:

    (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))
    

    在repl中:

    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]]