Y a-t-il une différence entre :::
et ++
pour concaténer les listes dans Scala?
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
D’après la documentation, ++
semble être plus général alors que :::
est spécifique à la List
. Ce dernier est-il fourni car il est utilisé dans d’autres langages fonctionnels?
Héritage. La liste a été initialement définie pour être à l’étude des langages fonctionnels:
1 :: 2 :: Nil // a list list1 ::: list2 // concatenation of two lists list match { case head :: tail => "non-empty" case Nil => "empty" }
Bien entendu, Scala a développé d’autres collections, de manière ponctuelle. À la sortie de la version 2.8, les collections ont été repensées pour une réutilisation maximale du code et une API cohérente, de sorte que vous pouvez utiliser ++
pour concaténer deux collections – et même des iterators. List, cependant, doit garder ses opérateurs d’origine, à part un ou deux qui ont été déconseillés.
:::
ne fonctionne qu’avec des listes, alors que ++
peut être utilisé avec n’importe quel parcours. Dans l’implémentation actuelle (2.9.0), ++
repose sur :::
si l’argument est également une List
.
Toujours utiliser :::
. Il y a deux raisons: l’efficacité et la sécurité de type.
Efficacité
x ::: y ::: z
est plus rapide que x ++ y ++ z
, car :::
est associatif correct. x ::: y ::: z
est analysé en tant que x ::: (y ::: z)
, qui est algorithmiquement plus rapide que (x ::: y) ::: z
(ce dernier nécessite O (| x |) plus d’étapes).
Type de sécurité
Avec :::
vous ne pouvez concaténer que deux List
. Avec ++
vous pouvez append n’importe quelle collection à List
, ce qui est terrible:
scala> List(1, 2, 3) ++ "ab" res0: List[AnyVal] = List(1, 2, 3, a, b)
++
est également facile à mélanger avec +
:
scala> List(1, 2, 3) + "ab" res1: Ssortingng = List(1, 2, 3)ab
Un point différent est que la première phrase est analysée comme suit:
scala> List(1,2,3).++(List(4,5)) res0: List[Int] = List(1, 2, 3, 4, 5)
Considérant que le deuxième exemple est analysé comme suit:
scala> List(4,5).:::(List(1,2,3)) res1: List[Int] = List(1, 2, 3, 4, 5)
Donc, si vous utilisez des macros, vous devriez faire attention.
En outre, ++
pour deux listes appelle :::
mais avec plus de surcharge car il demande une valeur implicite pour avoir un générateur de List to List. Mais les microbenchmarks n’ont rien d’utile en ce sens, je suppose que le compilateur optimise ces appels.
Micro-Benchmarks après échauffement.
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
Comme l’a dit Daniel C. Sobrai, vous pouvez append le contenu de toute collection à une liste en utilisant ++
, alors qu’avec :::
vous ne pouvez que concaténer des listes.