Mar 9 2009

Confused with Ranges

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 def a = ['a', 'b', 'c', 'd', 'e']

Elementy posiadają indeksy od 0 do 4, jednak w groovym dodatkowo posiadają indeksy od -5 do -1 .

   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 assert a[0] == 'a'
 2 assert a[-5] == 'a'

Możemy pobierać elementy tablicy za pomocą Range:

 1 assert a[0..3] == ['a', 'b', 'c', 'd']

lub w odwrotnej kolejności:

 1 assert a[-1..-5] == ['e', 'd', 'c', 'b', 'a']

Teraz porównywanie ‘do’:

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

   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 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 assert a[4..<1]  == ['e', 'd', 'c']
  • Wykop
  • Blip
  • Twitter
  • Facebook
  • DZone
  • Digg
  • Blinklist
  • Delicious
  • Evernote
  • LinkedIn
  • Google Bookmarks
  • Google Buzz
  • Google Reader
  • Share/Bookmark