以下Groovy代码
lines = ['0','1','2','3','4','5']
println lines[1..lines.size()-1]
println lines[1..-1]
println lines[1..<lines.size()-1]
println lines[1..<-1]
println lines[1..<-2]
println lines[1..-2]
生成此输出:
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 2, 3, 4]
[1, 0]
[1, 2, 3, 4, 5]
[1, 2, 3, 4]
由于-1
是列表中最后一个元素的索引,前两个是有意义的(Groovy中的范围包括end元素,而不是像Java中的其他地方一样省略它:-()
第3行是所需的输出(没有第一个和最后一个元素的列表)。
我担心输出#4:为什么我[1, 0]
获得1..-1
?
范围[1, 2, 3, 4, 5]
的{{1}}似乎也是错误的。
为什么会这样?
答案 0 :(得分:17)
在我看来,采用所有元素但最后一个元素的最佳方法是使用take
方法:
def list = ['a', 'b', 'c']
assert list.take(list.size() - 1) == ['a', 'b']
在大小== 1:
的角落情况下它表现正常def list = ['one']
assert list.take(list.size() - 1) == []
虽然我更喜欢在大小== 0的情况下抛出异常,但行为并不是那么糟糕:
def list = []
assert list.take(list.size() - 1) == []
您也可以使用list[0..<list.size()-1]
(您的第三个示例),除了空列表外,它的行为相同,在这种情况下,它会抛出ArrayIndexOutOfBoundsException
,但我认为不像take
对应方。
另一个可接受的解决方案是使用list[0..-2]
(您的上一个示例),我认为这看起来更优雅,但不幸的是,当尺寸== 1且ArrayIndexOutOfBoundsException
时会中断。
在你的例子中(我假设你想用0作为起始索引而不是1如果你想包括所有元素而不是最后一个):
lines[0..lines.size()-1]
相当于lines[0..-1]
,因为getAt(Range)
列表方法会将负索引的范围与getAt(Integer)
的方式相同,即访问{{1}列表的元素。因此(list.size() + negativeIndex)
与“从第一个元素到最后一个元素”的说法相同,它与复制列表相同;和list[0..-1]
与“从最后到第一个”相同,它相当于list[-1..0]
:)
其他非包含范围示例的问题是在列表访问之前正在评估非包含范围,并且它们评估为不正确的包含范围。例如,list.reverse()
评估为0..<-2
,这就是它返回所有元素的原因。 0..-1
评估为0..<-1
,它只返回第一个元素。
请注意,空范围是一种特殊情况。它表示为0..0
,并且没有包含等价物(因此Groovy不会在此处进行任何魔术转换)。这就是为什么0..<0
在size == 1(范围评估为空范围)时工作的原因,而list[0..<list.size()-1]
没有:)
答案 1 :(得分:4)
自从流行者写下他的答案以来,这可能已经发生了变化,但你可以在没有最后一个元素0..<-1
的情况下获得整个列表:
assert ["foo"][0..<-1] == []
assert ["foo", "bar"][0..<-1] == ["foo"]
assert ["foo", "bar", "baz"][0..<-1] == ["foo", "bar"]
// blows up if empty, here take is better
assert [][0..<-1] == [] // BOOM
// if you want null safe, use take
assert [].take(-1) == []
这是groovy 2.2.1。
答案 2 :(得分:2)