Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get all elements from a list without the last element?

Tags:

groovy

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?

like image 397
Aaron Digulla Avatar asked May 09 '12 12:05

Aaron Digulla


People also ask

How do I remove the last entry from a list in Python?

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.

How do I remove the last 3 elements from a list in Python?

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.

How do you find the last element of a list without using Len?

For any list, accessing the index of [-1] will return the last element of the list without needing to use the len() function.


1 Answers

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 :)

like image 116
epidemian Avatar answered Oct 06 '22 07:10

epidemian