[英]Clojure - Merge two vectors of vectors different sizes
Here I am again facing some problems with Clojure.在这里,我再次面临 Clojure 的一些问题。 I have two vectors of vectors.我有两个向量向量。
[[a b c] [d e f] [g h i]]
and和
[[a b] [d e] [g h] [j k]]
And I wanna merge these two in a way that the final vector would be something like this:我想以某种方式合并这两个,最终向量将是这样的:
[[a b c] [d e f] [g h i] [j k l]]
In the output, the last item [jkl], the L is a constant value when there is no value to merge (because it has no corresponding item in the first vector. How can I do such thing?在输出中,最后一项[jkl],L在没有要合并的值时是一个常数值(因为它在第一个向量中没有对应的项。我该怎么做?
PS: I am new to Clojure and I appreciate a elaborated answer so that I could understand better. PS:我是 Clojure 的新手,我很欣赏详细的答案,以便我能更好地理解。 Also, sorry if this is a trivial question.另外,对不起,如果这是一个微不足道的问题。
In general:一般来说:
So in this case your problem can be broken down into:因此,在这种情况下,您的问题可以分解为:
So if I make a couple assumptions about your problem here is an example of breaking it down and building it back up:因此,如果我对您的问题做出几个假设,这里有一个分解并重新构建它的示例:
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
make a function to choose the correct pair of the overlapping parts.制作一个函数来选择正确的重叠部分对。 I chose length though you can merge these however you want:我选择了长度,尽管您可以根据需要合并这些:
user> (defn longer-list [x y]
(if (> (count x) (count y))
x
y))
#'user/longer-list
make a function to pad out a list that's too short制作一个函数来填充一个太短的列表
user> (defn pad-list [l min-len default-value]
(into l (take (- min-len (count l)) (repeat default-value))))
#'user/pad-list
Make a function that uses these two functions to split and then recombine the parts of the problem:制作一个函数,使用这两个函数进行拆分,然后重新组合问题的各个部分:
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
and then test it :-)然后测试它:-)
user> (process-list a b)
([a b c] [d e f] [g h i] [j k l])
There are more details to work out, like what happens when the lists-of-lists are the same length, and if they are not subsets of each other.还有更多的细节需要解决,比如当列表的列表长度相同时会发生什么,如果它们不是彼此的子集。 (and yes you can smash this down to a "one liner" too) (是的,您也可以将其粉碎为“单衬”)
i would generally go with the following approach:我通常会采用以下方法:
It is better to illustrate it with code:最好用代码来说明:
first of all let's make up some helper functions:首先让我们组成一些辅助函数:
(defn max-count [coll1 coll2] (max (count coll1) (count coll2)))
it's name says for itself.它的名字不言而喻。
(defn fill-up-to [coll size] (take size (concat coll (repeat nil))))
this one fills the collection with nil
s up to some size:这个用nil
填充集合到一定大小:
user> (fill-up-to [1 2 3] 10)
(1 2 3 nil nil nil nil nil nil nil)
now the merge function:现在合并功能:
(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))))
the outer mapv
operates on collections made from initial parameters filled up to the length of the longest one ( coll-len
), so in context of the question it will be:外部mapv
对由填充到最长参数( coll-len
)长度的初始参数组成的集合进行操作,因此在问题的上下文中,它将是:
(mapv some-fn [[a b c] [d e f] [g h i] nil]]
[[a b] [d e] [g h] [j k]])
the inner mapv operates on inner vectors, filled up to the comp-len
(3 in this case):内部 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])
let's test it:让我们测试一下:
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]]
ok it works just as we wanted.好的,它就像我们想要的那样工作。
now if you look at the merge-colls
, you may notice the repetition of the pattern:现在,如果您查看merge-colls
,您可能会注意到模式的重复:
(mapv some-fn (fill-up-to coll1 size)
(fill-up-to coll2 size))
we can eliminate the duplication by moving this pattern out to a function:我们可以通过将这种模式移出一个函数来消除重复:
(defn mapv-equalizing [map-fn size coll1 coll2]
(mapv map-fn (fill-up-to coll1 size) (fill-up-to coll2 size)))
and rewrite our merge:并重写我们的合并:
(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)))
test:测试:
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]]
ok.好的。 now we can shorten it by removing collection size bindings, as we need these values just once:现在我们可以通过删除集合大小绑定来缩短它,因为我们只需要一次这些值:
(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))
in 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]]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.