为什么在组合()上有不同的行为,如果在Groovy / Spock中使用空列表?

时间:2013-12-16 21:58:12

标签: groovy spock

我们在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()

[]

任何人都对这里发生的事情有任何解释?为什么完全不同的行为取决于空列表出现的位置?我们想了解规则,以便我们可以正确使用这种组合()。

1 个答案:

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