The following Groovy code
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]
produces this output:
[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]
Since -1
is the index of the last element in the list, the first two make sense (ranges in Groovy include the end element instead of omitting it as everywhere else in Java :-( )
Line #3 is the desired output (list without first and last element).
I'm worried about the output #4: Why do I get [1, 0]
for 1..-1
?
Also [1, 2, 3, 4, 5]
for the range 1..<-2
seems wrong.
Why does that happen?
The del operator deletes the element at the specified index location from the list. To delete the last element, we can use the negative index -1. The use of the negative index allows us to delete the last element, even without calculating the length of the list.
Python3. Method 3: Using pop() method: the pop() method will remove the last element from the list, So to remove last k elements from the python list, we need to perform the pop() operation k times.
For any list, accessing the index of [-1] will return the last element of the list without needing to use the len() function.
The best way to take all elements but the last one, in my opinion, is to use the take
method:
def list = ['a', 'b', 'c']
assert list.take(list.size() - 1) == ['a', 'b']
It behaves properly in the corner case where size == 1:
def list = ['one']
assert list.take(list.size() - 1) == []
Though I'd prefer it to throw an exception in the case size == 0, but the behavior is not that bad:
def list = []
assert list.take(list.size() - 1) == []
You can also use list[0..<list.size()-1]
(your third example) and it will behave the same except for the empty list, in which case it will throw an ArrayIndexOutOfBoundsException
, but i think is not as readable as the take
counterpart.
Another acceptable solution is using list[0..-2]
(your last example), which i think looks much more elegant, but unfortunately breaks when size == 1 with an ArrayIndexOutOfBoundsException
.
In your examples (i'll assume that you meant to use 0 as the starting index instead of 1 if you wanted to include all elements but the last one):
lines[0..lines.size()-1]
is equivalent to lines[0..-1]
because the getAt(Range)
method of lists will treat ranges with negative indexes the same way asgetAt(Integer)
does, i.e. as accessing the (list.size() + negativeIndex)
'th element of the list. Therefore list[0..-1]
is the same as saying "from first element to last" and it's the same as copying the list; and list[-1..0]
is the same as "from last to first" and it's equivalent to list.reverse()
:)
The problem with the other non-inclusive range example is that the non-inclusive ranges are being evaluated before the list access and they evaluate to an incorrect inclusive range. For example, 0..<-2
evaluates to 0..-1
, and that's why it's returning all the elements. 0..<-1
evaluates to 0..0
and it returns only the first element.
Notice that the empty range is a special case. It's denoted as 0..<0
and it doesn't have an inclusive equivalent (so Groovy won't do any magic conversion here). And that's why list[0..<list.size()-1]
works when size == 1 (the range evaluates to the empty range) while list[0..-2]
doesn't :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With