我们在Spock中遇到了一个奇怪的combination()行为,它与空列表的交互。
1)一个工作正常的简单案例
def testa = [[1,2], [2,3], [3,4]].combinations()
[[1, 2, 3], [2, 2, 3],
[1, 3, 3], [2, 3, 3],
[1, 2, 4], [2, 2, 4],
[1, 3, 4], [2, 3, 4]]
2)当你在列表的头部传递一个空字符串时,它似乎忽略了第一个条目并产生了一些合理的东西:
def testb = [[], [2,3], [3,4]].combinations()
[[2, 3], [3, 3], [2, 4], [3, 4]]
3)但....当你把一个空字符串传递给开头以外的任何地方时,它似乎忽略了它之前的一切:
def testc = [[1,2], [], [3,4]].combinations()
[[3], [4]]
这是另一个例子:
def testd = [[1,2], [2,3], []].combinations()
[]
任何人都对这里发生的事情有任何解释?为什么完全不同的行为取决于空列表出现的位置?我们想了解规则,以便我们可以正确使用这种组合()。
答案 0 :(得分:1)
我们可以though the source of combinations
工作,并了解它的作用。
在这里,我已将其转换为Groovy,并添加了调试,以便我们可以看到它在做什么:
List combinations( Iterable collections ) {
List collectedCombos = []
collections.each { collection ->
collection = collection instanceof Collection ? collection : [ collection ]
println "Handling $collection"
if( collectedCombos.isEmpty() ) {
collectedCombos = collection.collect { item -> [ item ] }
println "collectedCombos was empty, is now: $collectedCombos"
}
else {
collectedCombos = collection.collectMany { value ->
print "Appending $value to $collectedCombos"
def result = collectedCombos.collect { List savedCombo ->
savedCombo.collect() << value
}
println " gave us $result"
result
}
println "So now, collectedCombos is $collectedCombos"
}
}
collectedCombos
}
所以,如果我们给它:
combinations( [[1,2], [2,3], [3,4]] )
我们得到输出:
Handling [1, 2]
collectedCombos was empty, is now: [[1], [2]]
Handling [2, 3]
Appending 2 to [[1], [2]] gave us [[1, 2], [2, 2]]
Appending 3 to [[1], [2]] gave us [[1, 3], [2, 3]]
So now, collectedCombos is [[1, 2], [2, 2], [1, 3], [2, 3]]
Handling [3, 4]
Appending 3 to [[1, 2], [2, 2], [1, 3], [2, 3]] gave us [[1, 2, 3], [2, 2, 3], [1, 3, 3], [2, 3, 3]]
Appending 4 to [[1, 2], [2, 2], [1, 3], [2, 3]] gave us [[1, 2, 4], [2, 2, 4], [1, 3, 4], [2, 3, 4]]
So now, collectedCombos is [[1, 2, 3], [2, 2, 3], [1, 3, 3], [2, 3, 3], [1, 2, 4], [2, 2, 4], [1, 3, 4], [2, 3, 4]]
并使用初始空集运行:
combinations( [[], [2,3], [3,4]] )
导致isEmpty
条件触发两次:
Handling []
collectedCombos was empty, is now: []
Handling [2, 3]
collectedCombos was empty, is now: [[2], [3]]
Handling [3, 4]
Appending 3 to [[2], [3]] gave us [[2, 3], [3, 3]]
Appending 4 to [[2], [3]] gave us [[2, 4], [3, 4]]
So now, collectedCombos is [[2, 3], [3, 3], [2, 4], [3, 4]]
将空列表放在中间:
combinations( [[1,2], [], [3,4]] )
节目:
Handling [1, 2]
collectedCombos was empty, is now: [[1], [2]]
Handling []
So now, collectedCombos is []
Handling [3, 4]
collectedCombos was empty, is now: [[3], [4]]
如您所见,没有为第二个元素循环生成数据,然后这个空列表会覆盖我们原来的任何数据。
对于第三种情况,它将是相同的,但由于空列表是最后一个,结果将是一个空列表。
希望这能解释一下吗?
如果您想在输入列表中处理空列表,那么您可以执行以下操作:
[[1,2], [], [3,4]].findResults { it ?: [ 'x' ] }.combinations()
给予:
[[1,'x',3], [2,'x',3], [1,'x',4], [2,'x',4]]