Ricerca…


Ordina una lista

Supponendo che il seguente elenco possiamo ordinare una varietà di modi.

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

Il comportamento predefinito di sorted() consiste nell'utilizzare math.Ordering , che per le stringhe restituisce un ordinamento lessografico :

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

sortWith consente di fornire il proprio ordine utilizzando una funzione di confronto:

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

sortBy ti consente di fornire una funzione di trasformazione:

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

Puoi sempre invertire una lista, o una lista ordinata, usando `reverse:

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

Gli elenchi possono anche essere ordinati utilizzando il metodo Java java.util.Arrays.sort e il suo wrapper Scala scala.util.Sorting.quickSort

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

Questi metodi possono migliorare le prestazioni quando si ordinano raccolte più grandi, se è possibile evitare le conversioni di raccolta e di disimballaggio / boxing. Per una discussione più dettagliata sulle differenze di prestazioni, leggi su Scala Collection ordinata, sortWith e sortBy Performance .

Crea una lista contenente n copie di x

Per creare una raccolta di n copie di qualche oggetto x , utilizzare il metodo di riempimento . Questo esempio crea un List , ma può funzionare con altre raccolte per le quali il fill ha senso:

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

Lista e trucchi di vettore

Ora è preferibile utilizzare Vector anziché List perché le implementazioni hanno prestazioni migliori. Le caratteristiche di prestazione possono essere trovate qui . Vector può essere utilizzato ovunque sia utilizzato List .

Creazione di 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

Prendi l'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

Prepend gli elementi

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

Aggiungi elementi

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

Iscriviti (Concatena) Elenchi

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)

Operazioni comuni

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"

Tagliere di raccolta mappe

Nota che questo riguarda la creazione di una raccolta di tipo Map , che è distinta dal metodo della map .

Creazione della mappa

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

Una mappa può essere considerata una raccolta di tuples per la maggior parte delle operazioni, in cui il primo elemento è la chiave e il secondo è il valore.

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

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

Aggiungi elemento (i)

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)

Operazioni comuni

Nelle operazioni in cui si verifica un'iterazione su una mappa ( map , find , forEach , ecc.), Gli elementi della raccolta sono tuples . Il parametro della funzione può utilizzare gli accessor tuple ( _1 , _2 ) o una funzione parziale con un blocco di casi:

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

Mappa e filtra su una collezione

Carta geografica

"Mappatura" su una raccolta utilizza la funzione map per trasformare ogni elemento di quella raccolta in un modo simile. La sintassi generale è:

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

Puoi fornire una funzione anonima:

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

Moltiplicare i numeri interi per due

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

Filtro

filter viene utilizzato quando si desidera escludere o "filtrare" determinati elementi di una raccolta. Come con la map , la sintassi generale assume una funzione, ma quella funzione deve restituire un Boolean :

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

Puoi fornire direttamente una funzione anonima:

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

Controllo dei numeri di coppia

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)

Altri esempi di mappe e filtri

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 )

Introduzione alle Collezioni Scala

Il framework delle collezioni Scala, secondo i suoi autori , è progettato per essere facile da usare, conciso, sicuro, veloce e universale.

Il framework è costituito da tratti Scala che sono progettati per essere blocchi per la creazione di collezioni. Per maggiori informazioni su questi blocchi, leggi la panoramica ufficiale delle collezioni Scala .

Queste raccolte incorporate sono separate nei pacchetti immutabili e mutabili. Per impostazione predefinita, vengono utilizzate le versioni immutabili. Costruire un List() (senza importare nulla) costruirà una lista immutabile .

Una delle funzionalità più potenti del framework è l'interfaccia coerente e di facile utilizzo tra le raccolte affini. Ad esempio, sommando tutti gli elementi in una raccolta è uguale per Elenchi, Set, Vettori, Seq e Matrici:

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

Questi tipi affini ereditano dal tratto Traversable .

Ora è preferibile utilizzare Vector anziché List perché le implementazioni hanno prestazioni migliori. Le caratteristiche di prestazione possono essere trovate qui . Vector può essere utilizzato ovunque sia utilizzato List .

Tipi percorribili

Classi di raccolta che hanno l'attrezzo Traversable trait foreach ed ereditano molti metodi per eseguire operazioni comuni alle collezioni, che funzionano tutte in modo identico. Le operazioni più comuni sono elencate qui:

  • Mappa : map , flatMap e collect nuove collezioni applicando una funzione a ciascun elemento della raccolta 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")
  • Le conversioni - toList , toArray e molte altre operazioni di conversione cambiano la raccolta corrente in un tipo più specifico di raccolta. Questi sono in genere metodi preceduti da 'to' e il tipo più specifico (cioè 'tolist' converte in una List ).
val array: Array[Int] = List[Int](1, 2, 3).toArray // convert list of ints to array of ints
  • Le informazioni sulla dimensione - isEmpty , nonEmpty , size e hasDefiniteSize sono tutti metadati relativi al set. Ciò consente alle operazioni condizionali sulla raccolta o al codice di determinare la dimensione della raccolta, incluso se è infinita o discreta.
List().isEmpty // true
List(1).nonEmpty // true
  • Recupero degli elementi : head , last , find e le loro varianti di Option vengono utilizzate per recuperare il primo o l'ultimo elemento o trovare un elemento specifico nella raccolta.
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))
  • Test Element - exists , forall e count vengono usati per controllare le operazioni di questa raccolta per vedere se soddisfa un predicato.
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

piega

Il metodo fold esegue iterazioni su una raccolta, utilizzando un valore dell'accumulatore iniziale e applicando una funzione che utilizza ciascun elemento per aggiornare correttamente l'accumulatore:

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

Nell'esempio precedente, è stata fornita una funzione anonima a fold() . Puoi anche usare una funzione con nome che accetta due argomenti. Sopportando questo nel mio, l'esempio sopra può essere riscritto così:

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

La modifica del valore iniziale influirà sul risultato:

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

Il metodo fold ha due varianti: foldLeft e foldRight .

foldLeft() itera da sinistra a destra (dal primo elemento della raccolta fino all'ultimo in quell'ordine). foldRight() da destra a sinistra (dall'ultimo elemento al primo elemento). fold() scorre da sinistra a destra come foldLeft() . Infatti fold() chiama effettivamente foldLeft() internamente.

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

fold() , foldLeft() e foldRight() restituiranno un valore che ha lo stesso tipo con il valore iniziale che prende. Tuttavia, a differenza di foldLeft() e foldRight() , il valore iniziale assegnato a fold() può essere solo dello stesso tipo o di un supertipo del tipo della raccolta.

In questo esempio l'ordine non è rilevante, quindi puoi cambiare fold() in foldLeft() o foldRight() e il risultato rimarrà lo stesso. L'utilizzo di una funzione sensibile all'ordine altererà i risultati.

In caso di dubbio, preferisci foldLeft() su foldRight() . foldRight() è meno performante.

Per ciascuno

foreach è insolito tra gli iteratori delle collezioni in quanto non restituisce un risultato. Invece applica una funzione a ciascun elemento che ha solo effetti collaterali. Per esempio:

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

scala> x.foreach { println }
1
2
3

La funzione fornita a foreach può avere qualsiasi tipo di ritorno, ma il risultato verrà scartato . In genere foreach viene utilizzato quando sono desiderati effetti collaterali. Se si desidera trasformare i dati, prendere in considerazione l'utilizzo di map , filter , a for comprehension o un'altra opzione.

Esempio di risultati di scarto

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

Ridurre

I metodi reduceRight reduce() , reduceLeft() e reduceRight sono simili alle pieghe. La funzione passata per ridurre prende due valori e ne produce un terzo. Quando si opera in un elenco, i primi due valori sono i primi due valori nell'elenco. Il risultato della funzione e il successivo valore nell'elenco vengono quindi riapplicati alla funzione, producendo un nuovo risultato. Questo nuovo risultato viene applicato con il successivo valore dell'elenco e così via fino a quando non ci sono più elementi. Il risultato finale viene restituito.

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

Ci sono alcune differenze nel modo in cui le funzioni di riduzione funzionano rispetto alle funzioni di piega. Loro sono:

  1. Le funzioni di riduzione non hanno valore dell'accumulatore iniziale.
  2. Le funzioni di riduzione non possono essere chiamate su liste vuote.
  3. Le funzioni di riduzione possono solo restituire il tipo o il supertipo dell'elenco.


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow