Buscar..


Ordenar una lista

Suponiendo que en la siguiente lista podemos clasificar una variedad de formas.

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

El comportamiento predeterminado de sorted() es usar math.Ordering , que para cadenas da como resultado una ordenación lexográfica :

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

sortWith permite proporcionar su propio pedido utilizando una función de comparación:

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

sortBy permite proporcionar una función de transformación:

//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)

Siempre puede revertir una lista, o una lista ordenada, usando `reverse:

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

Las listas también se pueden ordenar utilizando el método Java java.util.Arrays.sort y su envoltorio Scala scala.util.Sorting.quickSort

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

Estos métodos pueden mejorar el rendimiento al ordenar colecciones más grandes si se pueden evitar las conversiones de colección y el desempaquetado / boxeo. Para una discusión más detallada sobre las diferencias de rendimiento, lea acerca de Scala Collection ordenados, sortWith y sortBy Performance .

Crear una lista que contenga n copias de x

Para crear una colección de n copias de algún objeto x , use el método de relleno . Este ejemplo crea una List , pero esto puede funcionar con otras colecciones para las que el fill tiene sentido:

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

Lista y Vector Cheatsheet

Ahora es una práctica recomendada utilizar Vector lugar de List porque las implementaciones tienen un mejor rendimiento Las características de rendimiento se pueden encontrar aquí . Vector se puede utilizar donde se utiliza la List .

Creación de listas

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

Tomar elemento

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

Elementos Prependidos

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

Anexar elementos

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

Unirse (concatenar) listas

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)

Operaciones comunes

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"

Mapa de la colección Cheatsheet

Tenga en cuenta que esto se refiere a la creación de una colección de tipo Map , que es distinta del método de map .

Creación de mapas

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

Un mapa puede considerarse una colección de tuples para la mayoría de las operaciones, donde el primer elemento es la clave y el segundo es el valor.

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

Obtener elemento

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)

Añadir elemento (s)

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)

Operaciones comunes

En las operaciones donde ocurre una iteración sobre un mapa ( map , find , forEach , etc.), los elementos de la colección son tuples . El parámetro de función puede usar los accesores de tupla ( _1 , _2 ), o una función parcial con un bloque de caso:

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

Mapa y filtro sobre una colección

Mapa

El 'Mapeo' a través de una colección usa la función de map para transformar cada elemento de esa colección de una manera similar. La sintaxis general es:

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

Puede proporcionar una función anónima:

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

Multiplicando números enteros por dos

// 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)

Filtrar

filter se utiliza cuando desea excluir o 'filtrar' ciertos elementos de una colección. Al igual que con map , la sintaxis general toma una función, pero esa función debe devolver un Boolean :

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

Puede proporcionar una función anónima directamente:

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

Comprobando los números de pares

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)

Más ejemplos de mapas y filtros

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 )

Introducción a las colecciones de Scala

El marco de Scala Collections, según sus autores , está diseñado para ser fácil de usar, conciso, seguro, rápido y universal.

El marco se compone de rasgos de Scala que están diseñados para ser bloques de construcción para crear colecciones. Para obtener más información sobre estos bloques de construcción, lea el resumen oficial de las colecciones de Scala .

Estas colecciones integradas se separan en los paquetes inmutables y mutables. Por defecto, se utilizan las versiones inmutables. Construir una List() (sin importar nada) construirá una lista inmutable .

Una de las características más poderosas del marco es la interfaz consistente y fácil de usar a través de colecciones afines. Por ejemplo, sumar todos los elementos en una colección es igual para Listas, Conjuntos, Vectores, Seqs y Arrays:

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

Estos tipos afines heredan del rasgo Traversable .

Ahora es una práctica recomendada utilizar Vector lugar de List porque las implementaciones tienen un mejor rendimiento Las características de rendimiento se pueden encontrar aquí . Vector se puede utilizar donde se utiliza la List .

Tipos transitables

Clases de colección que tienen el Traversable rasgo implementar foreach y heredar muchos métodos para realizar operaciones comunes a las colecciones, que todos funcionan de forma idéntica. Las operaciones más comunes se enumeran aquí:

  • Mapa - map , flatMap y collect producir nuevas colecciones mediante la aplicación de una función a cada elemento de la colección original.
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")
  • Conversiones : toList , toArray y muchas otras operaciones de conversión cambian la colección actual en un tipo más específico de colección. Por lo general, estos son métodos prependidos con 'to' y el tipo más específico (es decir, 'toList' se convierte en una List ).
val array: Array[Int] = List[Int](1, 2, 3).toArray // convert list of ints to array of ints
  • Información de tamaño : isEmpty , nonEmpty , size y hasDefiniteSize son todos metadatos sobre el conjunto. Esto permite operaciones condicionales en la colección, o para que el código determine el tamaño de la colección, incluso si es infinito o discreto.
List().isEmpty // true
List(1).nonEmpty // true
  • Recuperación de elementos : head , last , find y sus variantes de Option se utilizan para recuperar el primer o último elemento, o encontrar un elemento específico en la colección.
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))
  • Pruebas de elementos - exists , forall , y count se utilizan operaciones de control de esta colección para ver si satisface un predicado.
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

Doblez

El método de fold recorre una colección, utilizando un valor inicial del acumulador y aplicando una función que utiliza cada elemento para actualizar el acumulador con éxito:

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

En el ejemplo anterior, se proporcionó una función anónima para fold() . También puede usar una función nombrada que toma dos argumentos. Teniendo esto en mi, el ejemplo anterior se puede reescribir así:

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

Cambiar el valor inicial afectará el resultado:

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

El método de fold tiene dos variantes: foldLeft y foldRight .

foldLeft() itera de izquierda a derecha (desde el primer elemento de la colección hasta el último en ese orden). foldRight() itera de derecha a izquierda (desde el último elemento hasta el primer elemento). fold() itera de izquierda a derecha como foldLeft() . De hecho, fold() realidad llama a foldLeft() internamente.

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

fold() , foldLeft() y foldRight() devolverá un valor que tiene el mismo tipo con el valor inicial que toma. Sin embargo, a diferencia de foldLeft() y foldRight() , el valor inicial dado para fold() solo puede ser del mismo tipo o un supertipo del tipo de la colección.

En este ejemplo, el orden no es relevante, por lo que puede cambiar fold() por foldLeft() o foldRight() y el resultado seguirá siendo el mismo. El uso de una función que sea sensible al orden alterará los resultados.

En caso de duda, prefiera foldLeft() sobre foldRight() . foldRight() tiene menos rendimiento.

Para cada

foreach es inusual entre los iteradores de colecciones porque no devuelve un resultado. En su lugar, aplica una función a cada elemento que tiene solo efectos secundarios. Por ejemplo:

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

scala> x.foreach { println }
1
2
3

La función suministrada a foreach puede tener cualquier tipo de retorno, pero el resultado se descartará . Normalmente se usa foreach cuando los efectos secundarios son deseables. Si desea transformar los datos, considere usar un map , un filter , una for comprehension u otra opción.

Ejemplo de descarte de resultados.

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

Reducir

Los métodos reduce() , reduceLeft() y reduceRight son similares a los pliegues. La función pasada para reducir toma dos valores y produce un tercero. Cuando se opera en una lista, los dos primeros valores son los dos primeros valores de la lista. El resultado de la función y el siguiente valor en la lista se vuelven a aplicar a la función, produciendo un nuevo resultado. Este nuevo resultado se aplica con el siguiente valor de la lista y así sucesivamente hasta que no haya más elementos. Se devuelve el resultado final.

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

Existen algunas diferencias en cómo funcionan las funciones de reducción en comparación con las funciones de plegado. Son:

  1. Las funciones de reducción no tienen valor acumulador inicial.
  2. Las funciones de reducción no se pueden llamar en listas vacías.
  3. Las funciones de reducción solo pueden devolver el tipo o supertipo de la lista.


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow