Recherche…


Trier une liste

En supposant la liste suivante, nous pouvons trier une variété de manières.

val names = List("Kathryn", "Allie", "Beth", "Serin", "Alana")

Le comportement par défaut de math.Ordering sorted() consiste à utiliser math.Ordering , qui pour les chaînes génère un tri lexographique :

names.sorted
// results in: List(Alana, Allie, Beth, Kathryn, Serin)

sortWith vous permet de fournir votre propre commande en utilisant une fonction de comparaison:

names.sortWith(_.length < _.length)
// results in: List(Beth, Allie, Serin, Alana, Kathryn)

sortBy vous permet de fournir une fonction de transformation:

//A set of vowels to use
val vowels = Set('a', 'e', 'i', 'o', 'u')

//A function that counts the vowels in a name
def countVowels(name: String) = name.count(l => vowels.contains(l.toLower))

//Sorts by the number of vowels
names.sortBy(countVowels)
//result is: List(Kathryn, Beth, Serin, Allie, Alana)

Vous pouvez toujours inverser une liste ou une liste triée en utilisant `reverse:

names.sorted.reverse
//results in: List(Serin, Kathryn, Beth, Allie, Alana)

Les listes peuvent également être triées à l'aide de la méthode Java java.util.Arrays.sort et de son wrapper Scala scala.util.Sorting.quickSort

java.util.Arrays.sort(data)
scala.util.Sorting.quickSort(data)

Ces méthodes peuvent améliorer les performances lors du tri de collections plus volumineuses si les conversions de collections et le déballage / la boxe peuvent être évités. Pour une discussion plus détaillée sur les différences de performances, consultez l'article Scala Collection trié, trié et triBy Performance .

Créer une liste contenant n copies de x

Pour créer une collection de n copies d'un objet x , utilisez la méthode de remplissage . Cet exemple crée une List , mais cela peut fonctionner avec d'autres collections pour lesquelles le fill sens:

// List.fill(n)(x)
scala > List.fill(3)("Hello World")
res0: List[String] = List(Hello World, Hello World, Hello World)

Cheatsheet Liste et Vecteur

Il est désormais recommandé d'utiliser le Vector plutôt que la List car les implémentations ont de meilleures performances. Les caractéristiques de performances peuvent être trouvées ici . Vector peut être utilisé partout où la List est utilisée.

Création de liste

List[Int]()         // Declares an empty list of type Int
List.empty[Int]     // Uses `empty` method to declare empty list of type Int
Nil                 // A list of type Nothing that explicitly has nothing in it

List(1, 2, 3)       // Declare a list with some elements
1 :: 2 :: 3 :: Nil  // Chaining element prepending to an empty list, in a LISP-style

Prendre élément

List(1, 2, 3).headOption // Some(1)
List(1, 2, 3).head       // 1

List(1, 2, 3).lastOption // Some(3)
List(1, 2, 3).last       // 3, complexity is O(n)

List(1, 2, 3)(1)         // 2, complexity is O(n)
List(1, 2, 3)(3)         // java.lang.IndexOutOfBoundsException: 4

Éléments complémentaires

0 :: List(1, 2, 3)       // List(0, 1, 2, 3)

Ajouter des éléments

List(1, 2, 3) :+ 4       // List(1, 2, 3, 4), complexity is O(n)

Rejoindre (concaténer) les listes

List(1, 2) ::: List(3, 4) // List(1, 2, 3, 4)
List.concat(List(1,2), List(3, 4)) // List(1, 2, 3, 4)
List(1, 2) ++ List(3, 4)  // List(1, 2, 3, 4)

Opérations communes

List(1, 2, 3).find(_ == 3)                     // Some(3)
List(1, 2, 3).map(_ * 2)                       // List(2, 4, 6)
List(1, 2, 3).filter(_ % 2 == 1)               // List(1, 3)
List(1, 2, 3).fold(0)((acc, i) => acc + i * i) // 1 * 1 + 2 * 2 + 3 * 3 = 14
List(1, 2, 3).foldLeft("Foo")(_ + _.toString)  // "Foo123"
List(1, 2, 3).foldRight("Foo")(_ + _.toString) // "123Foo"

Carte cheatsheet

Notez que cela concerne la création d'une collection de type Map , distincte de la méthode de map .

Création de carte

Map[String, Int]() 
val m1: Map[String, Int] = Map()
val m2: String Map Int = Map()

Une carte peut être considérée comme une collection de tuples pour la plupart des opérations, où le premier élément est la clé et le second la valeur.

val l = List(("a", 1), ("b", 2), ("c", 3))
val m = l.toMap                               // Map(a -> 1, b -> 2, c -> 3)

Get element

val m = Map("a" -> 1, "b" -> 2, "c" -> 3)

m.get("a")  // Some(1)
m.get("d")  // None
m("a")      // 1
m("d")      // java.util.NoSuchElementException: key not found: d

m.keys      // Set(a, b, c)
m.values    // MapLike(1, 2, 3)

Ajouter des éléments

Map("a" -> 1, "b" -> 2) + ("c" -> 3)               // Map(a -> 1, b -> 2, c -> 3)
Map("a" -> 1, "b" -> 2) + ("a" -> 3)               // Map(a -> 3, b -> 2)
Map("a" -> 1, "b" -> 2) ++ Map("b" -> 3, "c" -> 4) // Map(a -> 1, b -> 3, c -> 4)

Opérations communes

Dans les opérations où une itération sur une carte se produit ( map , find , forEach , etc.), les éléments de la collection sont des tuples . Le paramètre de fonction peut soit utiliser les accesseurs de tuple ( _1 , _2 ), soit une fonction partielle avec un bloc de casse:

m.find(_._1 == "a")  // Some((a,1))
m.map {
  case (key, value) => (value, key)
}                    // Map(1 -> a, 2 -> b, 3 -> c)
m.filter(_._2 == 2)  // Map(b -> 2)
m.foldLeft(0){
  case (acc, (key, value: Int)) => acc + value
}                    // 6

Carte et filtre sur une collection

Carte

«Mappage» dans une collection utilise la fonction de map pour transformer chaque élément de cette collection de la même manière. La syntaxe générale est la suivante:

val someFunction: (A) => (B) = ???
collection.map(someFunction)

Vous pouvez fournir une fonction anonyme:

collection.map((x: T) => /*Do something with x*/)

Multiplication des nombres entiers par deux

// Initialize 
val list = List(1,2,3)
// list: List[Int] = List(1, 2, 3)

// Apply map
list.map((item: Int) => item*2)
// res0: List[Int] = List(2, 4, 6)

// Or in a more concise way
list.map(_*2)
// res1: List[Int] = List(2, 4, 6)

Filtre

filter est utilisé lorsque vous souhaitez exclure ou filtrer certains éléments d'une collection. Comme avec map , la syntaxe générale prend une fonction, mais cette fonction doit renvoyer une valeur Boolean :

val someFunction: (a) => Boolean = ???
collection.filter(someFunction)

Vous pouvez fournir une fonction anonyme directement:

collection.filter((x: T) => /*Do something that returns a Boolean*/)

Vérification des numéros de paire

val list = 1 to 10 toList
// list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

// Filter out all elements that aren't evenly divisible by 2
list.filter((item: Int) => item % 2==0)
// res0: List[Int] = List(2, 4, 6, 8, 10)

Plus d'exemples de carte et de filtre

case class Person(firstName: String,
                  lastName: String,
                  title: String)

// Make a sequence of people
val people = Seq(
  Person("Millie", "Fletcher", "Mrs"),
  Person("Jim", "White", "Mr"),
  Person("Jenny", "Ball", "Miss") )


// Make labels using map
val labels = people.map( person =>
  s"${person.title}. ${person.lastName}"
)

// Filter the elements beginning with J
val beginningWithJ = people.filter(_.firstName.startsWith("J"))

// Extract first names and concatenate to a string
val firstNames = people.map(_.firstName).reduce( (a, b) => a + "," + b )

Introduction aux collections de la Scala

Selon ses auteurs , le cadre Scala Collections est conçu pour être facile à utiliser, concis, sûr, rapide et universel.

Le cadre est constitué de traits Scala conçus pour constituer des blocs de création de collections. Pour plus d'informations sur ces blocs de construction, lisez l'aperçu des collections Scala .

Ces collections intégrées sont séparées dans les packages immuables et mutables. Par défaut, les versions immuables sont utilisées. Construire une List() sans rien importer construira une liste immuable .

L’une des fonctionnalités les plus puissantes de l’infrastructure est l’interface cohérente et conviviale à travers des collections aux vues similaires. Par exemple, la somme de tous les éléments d’une collection est la même pour les listes, les ensembles, les vecteurs, les seqs et les tableaux:

val numList = List[Int](1, 2, 3, 4, 5)
numList.reduce((n1, n2) => n1 + n2)  // 15

val numSet = Set[Int](1, 2, 3, 4, 5)
numSet.reduce((n1, n2) => n1 + n2)   // 15

val numArray = Array[Int](1, 2, 3, 4, 5)
numArray.reduce((n1, n2) => n1 + n2) // 15

Ces types partageant les mêmes idées héritent du trait Traversable .

Il est désormais recommandé d'utiliser le Vector plutôt que la List car les implémentations ont de meilleures performances. Les caractéristiques de performances peuvent être trouvées ici . Vector peut être utilisé partout où la List est utilisée.

Types transversables

Classes de collection qui ont le Traversable trait mettre en œuvre foreach et héritera de nombreuses méthodes pour effectuer des opérations communes aux collections, toutes fonctionnent de manière identique. Les opérations les plus courantes sont répertoriées ici:

  • Map - map , flatMap et collect produisent de nouvelles collections en appliquant une fonction à chaque élément de la collection originale.
List(1, 2, 3).map(num => num * 2) // double every number = List(2, 4, 6)

// split list of letters into individual strings and put them into the same list
List("a b c", "d e").flatMap(letters => letters.split(" ")) // = List("a", "b", "c", "d", "e")
  • Conversions - toList , toArray et de nombreuses autres opérations de conversion transforment la collection actuelle en un type de collection plus spécifique. Ce sont généralement des méthodes précédées de «to» et du type plus spécifique (c.-à-d. «ToList» converti en une List ).
val array: Array[Int] = List[Int](1, 2, 3).toArray // convert list of ints to array of ints
  • Informations sur la taille - isEmpty , nonEmpty , size et hasDefiniteSize sont toutes des métadonnées sur l'ensemble. Cela permet aux opérations conditionnelles sur la collection ou au code de déterminer la taille de la collection, notamment si elle est infinie ou discrète.
List().isEmpty // true
List(1).nonEmpty // true
  • Récupération d'éléments - head , last , find et leurs variantes Option permettent de récupérer le premier ou le dernier élément ou de rechercher un élément spécifique dans la collection.
val list = List(1, 2, 3)
list.head // = 1
list.last // = 3
List(-2, -1, 0, 1, 2).filter(num => num > 0) // = List(1, 2)
// split numbers into < 0 and >= 0
List(-2, -1, 0, 1, 2).partition(num => num < 0) // = (List(-2, -1), List(0, 1, 2))
  • Les tests d'éléments - exists , forall et count sont des opérations utilisées pour vérifier cette collection pour voir si elle satisfait un prédicat.
List(1, 2, 3, 4).forall(num => num > 0) // = true, all numbers are positive
List(-3, -2, -1, 1).forall(num => num < 0) // = false, not all numbers are negative

Plier

La méthode fold itération sur une collection, en utilisant une valeur d'accumulateur initiale et en appliquant une fonction qui utilise chaque élément pour mettre à jour l'accumulateur avec succès:

val nums = List(1,2,3,4,5)
var initialValue:Int = 0;
var sum = nums.fold(initialValue){
  (accumulator,currentElementBeingIterated) => accumulator + currentElementBeingIterated
}
println(sum) //prints 15 because 0+1+2+3+4+5 = 15

Dans l'exemple ci-dessus, une fonction anonyme a été fournie pour fold() . Vous pouvez également utiliser une fonction nommée qui prend deux arguments. En prenant ceci dans mon, l'exemple ci-dessus peut être ré-écrit ainsi:

def sum(x: Int, y: Int) = x+ y
val nums = List(1, 2, 3, 4, 5)
var initialValue: Int = 0
val sum = nums.fold(initialValue)(sum)
println(sum) // prints 15 because 0 + 1 + 2 + 3 + 4 + 5 = 15

Changer la valeur initiale affectera le résultat:

initialValue = 2;
sum = nums.fold(initialValue){ 
 (accumulator,currentElementBeingIterated) => accumulator + currentElementBeingIterated
}
println(sum) //prints 17 because 2+1+2+3+4+5 = 17

La méthode fold a deux variantes - foldLeft et foldRight .

foldLeft() itère de gauche à droite (du premier élément de la collection au dernier dans cet ordre). foldRight() itère de droite à gauche (du dernier élément au premier élément). fold() itère de gauche à droite comme foldLeft() . En fait, fold() appelle en réalité foldLeft() interne.

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)

fold() , foldLeft() et foldRight() retourneront une valeur qui a le même type que la valeur initiale. Cependant, contrairement à foldLeft() et foldRight() , la valeur initiale donnée à fold() ne peut être que du même type ou d'un sur-type du type de la collection.

Dans cet exemple, l'ordre n'est pas pertinent, vous pouvez donc changer fold() en foldLeft() ou foldRight() et le résultat restera le même. L'utilisation d'une fonction sensible à l'ordre modifie les résultats.

En cas de doute, préférez foldLeft() sur foldRight() . foldRight() est moins performant.

Pour chaque

foreach est inhabituel parmi les itérateurs de collections en ce sens qu'il ne renvoie pas de résultat. Au lieu de cela, il applique une fonction à chaque élément qui n'a que des effets secondaires. Par exemple:

scala> val x = List(1,2,3)
x: List[Int] = List(1, 2, 3)

scala> x.foreach { println }
1
2
3

La fonction fournie à foreach peut avoir n'importe quel type de retour, mais le résultat sera ignoré . Typiquement, foreach est utilisé lorsque les effets secondaires sont souhaitables. Si vous souhaitez transformer des données, utilisez une map , un filter , une for comprehension ou une autre option.

Exemple de rejet des résultats

def myFunc(a: Int) : Int = a * 2
List(1,2,3).foreach(myFunc) // Returns nothing

Réduire

Les méthodes reduceRight reduce() , reduceLeft() et reduceRight sont similaires aux plis. La fonction passée à réduire prend deux valeurs et en génère une troisième. Lorsque vous utilisez une liste, les deux premières valeurs sont les deux premières valeurs de la liste. Le résultat de la fonction et la valeur suivante dans la liste sont ensuite réappliqués à la fonction, produisant un nouveau résultat. Ce nouveau résultat est appliqué avec la valeur suivante de la liste et ainsi de suite jusqu'à ce qu'il n'y ait plus d'éléments. Le résultat final est renvoyé.

val nums = List(1,2,3,4,5)
sum = nums.reduce({ (a, b) => a + b })
println(sum) //prints 15

val names = List("John","Koby", "Josh", "Matilda", "Zac", "Mary Poppins")

def findLongest(nameA:String, nameB:String):String = {
  if (nameA.length > nameB.length) nameA else nameB
}

def findLastAlphabetically(nameA:String, nameB:String):String = {
  if (nameA > nameB) nameA else nameB
}

val longestName:String = names.reduce(findLongest(_,_))
println(longestName) //prints Mary Poppins

//You can also omit the arguments if you want
val lastAlphabetically:String = names.reduce(findLastAlphabetically)
println(lastAlphabetically) //prints Zac

Il existe des différences dans le fonctionnement des fonctions de réduction par rapport aux fonctions de pliage. Elles sont:

  1. Les fonctions de réduction n'ont pas de valeur d'accumulateur initiale.
  2. Les fonctions de réduction ne peuvent pas être appelées sur des listes vides.
  3. Les fonctions Réduire ne peuvent que renvoyer le type ou le sur-type de la liste.


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow