Scala – pętle i listy

Kontynuuję przyglądanie się językowi Scala. Pomaga mi w tym książka Davida Pollaka Beginning Scala.

Przyjrzyjmy się jak w Scali wygląda obsługa pętli for:

scala> for {i <- 1 to 3} println(i)
1
2
3

scala> for {i for {i <- 1 to 3
j <- 1 to 3} println(i + j)
2
3
4
3
4
5
4
5
6

Jak widzimy – przy użyciu pojedynczego polecenia for – dość łatwo możemy tworzyć pętle zagnieżdżone. To nie koniec możliwości pętli for. Umożliwia nam ona ograniczanie zakresu pętli przez zwiększenie kroku, lub użycie funkcji sprawdzającej, czy dany element powinien być brany pod uwagę:

scala> for (i <- 1 to 9 by 3) println(i);
1
4
7

scala> for (i <- 1 to 9 if i % 3 == 1) println(i)
1
4
7

Pętla for wykorzystuje obiekty typu zakres (Range). Ciekawą jego własnością jest to, że elementy zakresu są fizycznie tworzone dopiero w momencie, gdy zostają one wykorzystane. Dzięki zakresom możemy również w bardzo prosty sposób tworzyć listy:

scala> (3 to 100 by 3).toList
res1: List[Int] = List(3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99)

scala> (for {i <- 1 to 100 if i % 3 == 0} yield i).toList
res2: List[Int] = List(3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99)

Listy można w łatwy sposób filtrować, usuwać, sortować, czy modyfikować elementy listy:

scala> (3 :: 6 :: 9 :: 12 :: Nil).filter(i => i % 2 == 0)
res4: List[Int] = List(6, 12)

scala> (3 :: 6 :: 9 :: 12 :: Nil).remove(i => i % 2 == 1)
res5: List[Int] = List(6, 12)

scala> (3 :: (6 :: (9 :: (12 :: Nil)))).sort(_ > _)
res6: List[Int] = List(12, 9, 6, 3)

scala> (3 :: 6 :: 9 :: 12 :: Nil).map(e => Math.pow(2,e).toInt)
res7: List[Int] = List(8, 64, 512, 4096)

Zauważmy, że Scala nie modyfikuje wartości pierwotnej listy. Wynikiem działania funkcji jest nowa lista elementów.

Scala umożliwia wykonywanie, w prosty sposób, bardziej skomplikowanych działań na listach. Funkcja reduceLeft rozpoczyna od skrajnie lewych elementów listy, wykonuje na nich zdefiniowaną funkcję i jej wynik przekazuje jako parametr do następnego wywołaniu funkcji. Jako drugi parametr przekazywany jest kolejny element listy. Operacja ta wykonywana jest dopóki nie zostaną przetworzone wszystkie elementy listy:

scala> List(3, 6, 9, 12).reduceLeft(_ + _)
res8: Int = 30

Podobną w działaniu funkcją jest funkcja foldLeft, jednak w tym przypadku wartość pierwsza wartość nie jest brana z listy, ale przekazywana jest jako parametr funkcji:

scala> List(3, 6, 9, 12).foldLeft("")(_.toString + "," + _.toString)
res9: java.lang.String = ,3,6,9,12

Oczywiście istnieją bliźniacze funkcje reduceRight i foldRight.

c.d.n.

Dodaj komentarz