Fajną nowością w języku Groovy, w porównianiu do języka Java są Ranges. Jest to kolekcja ( a dokładnie wyjasniając implementuje interfejs java.util.List ), która definiuje zasięg kolekcji – początek i koniec. Oznacza się go oddzielajac dwoma kropkami pierwszy element od ostatniego, np. 1..3 zawiera kolekcję liczb od 1 do 3 (włącznie), a 1..<3 zawiera kolekcję liczb od 1 do 3 (nie wliczając 3). Problem jest właśnie ze zrozumieniem jak działa ten znak miejszości.
Mamy na przykład w kodzie tablicę:
1 2 |
def a = ['a', 'b', 'c', 'd', 'e'] |
Elementy posiadają indeksy od 0 do 4, jednak w groovym dodatkowo posiadają indeksy od -5 do -1 .
1 2 3 4 |
a b c d e 0 1 2 3 4 -5 -4 -3 -2 -1 |
Dodatkowe indexy służą m.in. do pobierania elementów tablicy od końca.
1 2 3 |
assert a[0] == 'a' assert a[-5] == 'a' |
Możemy pobierać elementy tablicy za pomocą Range:
1 2 |
assert a[0..3] == ['a', 'b', 'c', 'd'] |
lub w odwrotnej kolejności:
1 2 |
assert a[-1..-5] == ['e', 'd', 'c', 'b', 'a'] |
Teraz porównywanie ‚do’:
1 2 |
assert a[0..<3] == ['a', 'b', 'c'] |
nie wlicza 3 do zasięgu, więc są wypisane elementy o indeksach 0, 1 i 2.
Jak to się ma przy indeksach ujemnych? Sprawdźmy:
1 2 |
assert a[-5..<-3] == ['a', 'b'] |
zasięg bierze indeksy DO 3 więc zaczynając od pierwszego -5 na -4 kończy. Czyli wszystko tak jak powinno.
Teraz zagadka:
biorąc pod uwagę, że elementy tablicy posiadają indeksy tak jak wyżej podano:
1 2 3 4 |
a b c d e 0 1 2 3 4 -5 -4 -3 -2 -1 |
Które elementy posiada subtablica a[0..<-3] ?
Logicznie rzecz biorąc index mniejszy od -3 = -4 . więc subtablica powinna zwierać elementy ‚a’ (index początkowy 0) i ‚b’ (indeks -4). Jednak wynik jest inny:
1 2 |
assert a[0..<-3] == ['a', 'b', 'c', 'd'] |
Jak to interpretować? Otóż we wszystkich podanych wyżej (oprócz ostatniego) przykładach początek zasięgu był mniejszy od końca ( a < b ). W ostatnim, początek jest większy od końca ( 0 > -3). Groovy zatem interpretuje taki zasięg jako odwrotny i znak mniejszości faktycznie również odwraca i traktuje jako znak większości. Czyli w powyższym przykładzie podaje jako koniec zasięgu index większy od -3 czyli -2. Z tego powodu mamy taki wynik.
Tak samo będzie w przypadku:
1 2 |
assert a[4..<1] == ['e', 'd', 'c'] |