Scala list concatenation,: vs ++
Czy jest jakaś różnica między :::
i ++
dla łączenia list w Scali?
scala> List(1,2,3) ++ List(4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)
scala> List(1,2,3) ::: List(4,5)
res1: List[Int] = List(1, 2, 3, 4, 5)
scala> res0 == res1
res2: Boolean = true
Z dokumentacja wygląda na to, że ++
jest bardziej ogólna, podczas gdy :::
jest List
-specyficzna. Czy ten ostatni jest dostępny, ponieważ jest używany w innych językach funkcyjnych?
4 answers
Dziedzictwo. Lista została pierwotnie zdefiniowana jako functional-languages-looking:
1 :: 2 :: Nil // a list
list1 ::: list2 // concatenation of two lists
list match {
case head :: tail => "non-empty"
case Nil => "empty"
}
Oczywiście Scala ewoluowała inne kolekcje, w sposób ad hoc. Po wydaniu 2.8 kolekcje zostały przeprojektowane dla maksymalnego ponownego użycia kodu i spójnego API, dzięki czemu można użyć {[1] } do połączenia dowolnych dwóch kolekcji -- a nawet iteratorów. Lista, jednak, musiał zachować swoje oryginalne operatorów, oprócz jednego lub dwóch, które zostały przestarzałe.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-25 21:22:54
Zawsze używaj :::
. Istnieją dwa powody: wydajność i bezpieczeństwo typu.
Wydajność
x ::: y ::: z
jest szybszy niż x ++ y ++ z
, Ponieważ {[2] } jest prawidłowy. {[3] } jest przetwarzane jako x ::: (y ::: z)
, co jest algorytmicznie szybsze niż (x ::: y) ::: z
(ta ostatnia wymaga O (|x|) więcej kroków).
Bezpieczeństwo typu
Z :::
możesz połączyć tylko dwa List
s. z ++
możesz dołączyć dowolny zbiór do List
, co jest straszne:
scala> List(1, 2, 3) ++ "ab"
res0: List[AnyVal] = List(1, 2, 3, a, b)
++
jest również łatwy do wymieszania z +
:
scala> List(1, 2, 3) + "ab"
res1: String = List(1, 2, 3)ab
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 08:13:57
:::
działa tylko z listami, podczas gdy ++
może być używany z dowolnym przejazdem. W obecnej implementacji (2.9.0), ++
wraca do :::
, jeśli argument jest również List
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-02 23:18:22
Inną kwestią jest to, że pierwsze zdanie jest przetwarzane jako:
scala> List(1,2,3).++(List(4,5))
res0: List[Int] = List(1, 2, 3, 4, 5)
Natomiast drugi przykład jest przetwarzany jako:
scala> List(4,5).:::(List(1,2,3))
res1: List[Int] = List(1, 2, 3, 4, 5)
Więc jeśli używasz makr, należy zachować ostrożność.
Poza tym, ++
dla dwóch list wywołuje :::
, ale z większym obciążeniem, ponieważ prosi o domyślną wartość, aby mieć konstruktora z listy do listy. Ale microbenchmarks nie udowodnił niczego użytecznego w tym sensie, myślę, że kompilator optymalizuje takie wywołania.
Mikro-Benchmarki po rozgrzaniu.
scala>def time(a: => Unit): Long = { val t = System.currentTimeMillis; a; System.currentTimeMillis - t}
scala>def average(a: () => Long) = (for(i<-1 to 100) yield a()).sum/100
scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ++ List(e) } })
res1: Long = 46
scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ::: List(e ) } })
res2: Long = 46
Jak powiedział Daniel C. Sobrai, możesz dodać zawartość dowolnej kolekcji do listy za pomocą ++
, podczas gdy za pomocą :::
możesz tylko łączyć listy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-02 19:26:41