通过groovy方式,代码如:
def l1 = [] as List;
def l2 = [] as List;
for(int i = 0; i < 5; i++) {
l1 << i;
l2 << i;
l1 << i;
}
println(l1);
println(l2);
def l = l1-l2;
println(l);
l是空的,但我希望它是[0,1,2,3,4],只需减去一次项目(如果只有l2中的项目)。
答案 0 :(得分:1)
它以这种方式工作,因为List.minus(Object el)
搜索匹配el
对象的所有元素,并将它们从输入列表中删除。或者,您可以使用List.removeElement(Object el)
搜索第一个元素并将其从列表中删除。此方法可以与Groovy的inject
方法结合使用:
def l1 = [] as List
def l2 = [] as List
for(int i = 0; i < 5; i++) {
l1 << i
l2 << i
l1 << i
}
def l3 = l2.inject(l1) { List list, el ->
list.removeElement(el)
return list
}
println "l1 is ${l1}"
println "l2 is ${l2}"
println "l3 is ${l3}"
输出:
l1 is [0, 0, 1, 1, 2, 2, 3, 3, 4, 4]
l2 is [0, 1, 2, 3, 4]
l3 is [0, 1, 2, 3, 4]
在此示例中,我们使用l2
列表来迭代其元素,并将l1
作为初始值传递给inject
方法。然后对于l2
列表中的每个元素,我们删除传递给inject方法的列表,然后返回它,所以在下一个迭代步骤中,这个列表在传递给{{1的闭包中被视为list
变量}}。 inject
是一种安全的方法,如果我们尝试删除列表中不存在的元素,则不会抛出异常。
但是,我向您展示的代码有一个明显的缺点 - 它将List.removeElement(Object el)
传递给inject方法,并且该列表会被它修改。这就是为什么当您最后打印l1
时,您会看到它与我们刚刚使用inject方法创建的l1
相等。这个问题的解决方案非常简单 - 您可以创建此列表的副本,而不是将参考传递给l3
。使用l1
和现在new ArrayList<>(l1)
列表不会被inject方法更新。
l1
希望它有所帮助。
答案 1 :(得分:1)
问题是删除是在元素相等的基础上完成的。
作为替代方案,您可以使用索引搜索较大的列表,并构建一个diff
列表,其中包含l1
中除第一个匹配索引之外的所有元素:
//find the first index of each l2 element in l1:
def match = l2.collect{l1.indexOf(it)}
//find indices of all elements that were not found in l1
def indices = (0..(-1+l1.size())).grep{!match.contains(it)}
//make a list of all elements that were not selected
//and that's basically the result of YOUR l1-l2
def diff = indices.collect{l1[it]}
println(diff)
输出:
[0, 1, 2, 3, 4]
请注意,这不是一般方法。它完全基于您上面的示例,并假设l1
是l2
的超集,但它提供了一个想法。