2012-05-09 31 views
12

Mã Groovy sauLàm thế nào để có được tất cả các yếu tố từ một danh sách không có phần tử cuối cùng?

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] 

sản xuất sản lượng này:

[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] 

Kể từ -1 là chỉ số của phần tử cuối cùng trong danh sách, là người đầu tiên hai có ý nghĩa (dãy trong Groovy bao gồm các yếu tố cuối thay vì bỏ qua nó như ở mọi nơi khác trong Java :-()

Dòng # 3 là đầu ra mong muốn (danh sách không có phần tử đầu tiên và cuối cùng)

Tôi lo lắng về kết quả # 4: Tại sao tôi nhận được [1, 0] cho 1..-1?

Ngoài ra [1, 2, 3, 4, 5] cho phạm vi 1..<-2 có vẻ sai.

Tại sao điều đó lại xảy ra?

+1

nên không phải là dãy bắt đầu từ 0 thay vì 1 nếu bạn muốn bao gồm tất cả các yếu tố nhưng cuối cùng? (trong ví dụ của bạn, bạn luôn loại trừ yếu tố đầu tiên) – epidemian

+0

Trong trường hợp của tôi, tôi cũng không muốn yếu tố đầu tiên nhưng đó không phải là điểm chính của câu hỏi của tôi. –

Trả lời

15

Cách tốt nhất để thực hiện tất cả các yếu tố nhưng người cuối cùng, theo ý kiến ​​của tôi, là sử dụng phương pháp take:

def list = ['a', 'b', 'c'] 
assert list.take(list.size() - 1) == ['a', 'b'] 

Nó cư xử đúng trong trường hợp góc trong đó kích thước == 1:

def list = ['one'] 
assert list.take(list.size() - 1) == [] 

Mặc dù tôi muốn nó để ném một ngoại lệ trong trường hợp kích thước == 0, nhưng hành vi đó không phải là xấu:

def list = [] 
assert list.take(list.size() - 1) == [] 

Bạn cũng có thể sử dụng list[0..<list.size()-1] (ví dụ thứ ba) và nó sẽ hoạt động giống như danh sách trống, trong trường hợp này nó sẽ ném ArrayIndexOutOfBoundsException, nhưng tôi nghĩ không thể đọc được như đối tác take.


Một giải pháp có thể chấp nhận được sử dụng list[0..-2] (ví dụ cuối cùng của bạn), mà tôi nghĩ rằng trông nhiều hơn nữa tao nhã, nhưng tiếc là phá vỡ khi kích thước == 1 với một ArrayIndexOutOfBoundsException.


Trong ví dụ của bạn (tôi sẽ cho rằng bạn có nghĩa là để sử dụng 0 như chỉ số bắt đầu thay vì 1 nếu bạn muốn bao gồm tất cả các yếu tố nhưng người cuối cùng):

lines[0..lines.size()-1] tương đương với lines[0..-1] vì phương pháp getAt(Range) sẽ xử lý các phạm vi có chỉ số âm theo cùng cách như getAt(Integer), chẳng hạn như truy cập vào phần tử thứ 1 của danh sách (list.size() + negativeIndex). Do đó, list[0..-1] giống như nói "từ phần tử đầu tiên đến cuối cùng" và nó giống như sao chép danh sách; và list[-1..0] giống với "từ cuối cùng đến đầu tiên" và tương đương với list.reverse() :)

Vấn đề với phạm vi không bao gồm khác là phạm vi không bao gồm đang được đánh giá trước khi truy cập danh sách và chúng đánh giá đến phạm vi bao gồm không chính xác. Ví dụ: 0..<-2 đánh giá là 0..-1 và đó là lý do tại sao nó trả về tất cả các yếu tố. 0..<-1 đánh giá là 0..0 và nó chỉ trả về phần tử đầu tiên.

Lưu ý rằng phạm vi trống là trường hợp đặc biệt. Nó được ký hiệu là 0..<0 và nó không có giá trị tương đương (vì vậy Groovy sẽ không thực hiện bất kỳ phép chuyển đổi nào ở đây). Và đó là lý do tại sao list[0..<list.size()-1] hoạt động khi kích thước == 1 (phạm vi đánh giá là phạm vi trống) trong khi list[0..-2] không :)

+1

+1 FWIW, chuyển đổi _'magic'_ [xảy ra ở đây] (https://github.com/groovy/groovy-core/blob/master/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java # L36) và đối tượng 'RangeInfo' được trả về [được sử dụng] (https://github.com/groovy/groovy-core/blob/master/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java# L4634) để gọi [Java tiêu chuẩn 'List.subList'] (http://docs.oracle.com/javase/6/docs/api/java/util/List.html#subList%28int,%20int%29) phương pháp –

3

Có thể điều này đã thay đổi kể từ khi epideman viết câu trả lời, nhưng bạn có thể lấy toàn bộ danh sách mà không có phần tử có 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) == [] 

Điều này là với cá bơn 2.2.1.

2

Kể từ Groovy 2.4 bạn có thể sử dụng phương pháp init():

lines = ['0','1','2','3','4','5'] 
assert lines.init() == ['0','1','2','3','4'] 
Các vấn đề liên quan