Sök…


Sortera en lista

Om vi antar följande lista kan vi sortera olika sätt.

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

Standardbeteendet för sorted() är att använda math.Ordering , vilket för strängar resulterar i en lexografisk sortering:

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

sortWith låter dig tillhandahålla din egen beställning genom att använda en jämförelsefunktion:

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

sortBy tillåter dig att tillhandahålla en transformationsfunktion:

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

Du kan alltid vända en lista eller en sorterad lista med "omvänd:

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

Listor kan också sorteras med Java-metoden java.util.Arrays.sort och dess Scala-omslag scala.util.Sorting.quickSort

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

Dessa metoder kan förbättra prestandan när du sorterar större samlingar om samlingskonvertering och unboxing / boxning kan undvikas. För en mer detaljerad diskussion om prestationsskillnader, läs om Scala Collection sorterade, sortWith och sortBy Performance .

Skapa en lista som innehåller n kopior av x

För att skapa en samling n kopior av något objekt x , använd fyllningsmetoden . Det här exemplet skapar en List , men det kan fungera med andra samlingar för vilka fill är vettigt:

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

Lista och vektorfusk

Det är nu en bra praxis att använda Vector istället för List eftersom implementeringarna har bättre prestanda Prestandaegenskaper finns här . Vector kan användas var List används.

Lista skapande

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

Ta element

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

Förbered element

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

Lägg till element

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

Gå med (sammanlänkade) listor

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)

Vanliga operationer

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"

Kartsamling Cheatsheet

Observera att detta handlar om att skapa en samling av typen Map , som skiljer sig från map metoden.

Skapa kartan

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

En karta kan betraktas som en samling tuples för de flesta operationer, där det första elementet är nyckeln och det andra är värdet.

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

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

Lägg till element

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)

Vanliga operationer

I operationer där en iteration över en karta inträffar ( map , find , för forEach osv.) forEach elementen i samlingen tuples . Funktionsparametern kan antingen använda tuple-accessorer ( _1 , _2 ) eller en partiell funktion med ett fallblock:

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

Karta och filtrera över en samling

Karta

'Mapping' över en samling använder map funktionen att transformera varje element i samlingen på ett liknande sätt. Den allmänna syntaxen är:

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

Du kan tillhandahålla en anonym funktion:

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

Multiplicera heltal med två

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

Filtrera

filter används när du vill utesluta eller "filtrera bort" vissa element i en samling. Liksom med map den allmänna syntaxen en funktion, men den funktionen måste returnera en Boolean :

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

Du kan tillhandahålla en anonym funktion direkt:

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

Kontrollerar parnumren

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)

Fler exempel på karta och filter

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 )

Introduktion till Scala-samlingar

Scala Collections-ramverket är enligt författarna utformat för att vara lätt att använda, kortfattat, säkert, snabbt och universellt.

Ramverket består av Scala- drag som är utformade som byggstenar för att skapa samlingar. För mer information om dessa byggstenar, läs den officiella översikten över Scala-samlingar .

Dessa inbyggda samlingar är separerade i de immutable och mutable paketen. Som standard används de immutable versionerna. Att konstruera en List() (utan att importera någonting) kommer att skapa en oföränderlig lista.

En av de mest kraftfulla funktionerna i ramverket är det konsekventa och lättanvända gränssnittet över likasinnade samlingar. Exempelvis är summan av alla element i en samling densamma för listor, uppsättningar, vektorer, sekvenser och matriser:

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

Dessa likasinnade typer ärver från Traversable egenskapen.

Det är nu en bra praxis att använda Vector istället för List eftersom implementeringarna har bättre prestanda Prestandaegenskaper finns här . Vector kan användas var List används.

Traversabla typer

Samlingsklasser som har Traversable drag implementerar foreach och ärver många metoder för att utföra vanliga operationer till samlingar, som alla fungerar identiskt. De vanligaste operationerna listas här:

  • Karta - map , flatMap och collect producerar nya samlingar genom att tillämpa en funktion på varje element i den ursprungliga samlingen.
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")
  • Konverteringar - toList , toArray och många andra konverteringsoperationer förändrar den aktuella samlingen till en mer specifik typ av samling. Det här är vanligtvis metoder förberedda med 'till' och den mer specifika typen (dvs. 'toList' konverteras till en List ).
val array: Array[Int] = List[Int](1, 2, 3).toArray // convert list of ints to array of ints
  • Storleksinfo - isEmpty , nonEmpty , size och hasDefiniteSize är alla metadata om uppsättningen. Detta tillåter villkorade operationer på samlingen, eller för kod för att avgöra storleken på samlingen, inklusive om det är oändligt eller diskret.
List().isEmpty // true
List(1).nonEmpty // true
  • Elementhämtning - head , last , find och deras Option används för att hämta det första eller det sista elementet, eller hitta ett specifikt element i samlingen.
val list = List(1, 2, 3)
list.head // = 1
list.last // = 3
  • Återvinning av undersamling - filter , tail , slice , drop och andra funktioner gör det möjligt att välja delar av samlingen att arbeta vidare.
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))
  • Elementtester - exists , för forall och count är operationer som används för att kontrollera denna samling för att se om den uppfyller ett predikat.
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

Vika ihop

fold iterates över en samling med ett initialt ackumuleringsvärde och tillämpar en funktion som använder varje element för att uppdatera ackumulatorn framgångsrikt:

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

I exemplet ovan levererades en anonym funktion för att fold() . Du kan också använda en namngiven funktion som tar två argument. Med detta i mitt kan exemplet ovan skrivas om så:

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

Ändring av det initiala värdet påverkar resultatet:

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

fold har två varianter - foldLeft och foldRight .

foldLeft() iterates från vänster till höger (från det första elementet i samlingen till det sista i den ordningen). foldRight() iterates från höger till vänster (från det sista elementet till det första elementet). fold() iterates från vänster till höger som foldLeft() . Faktum är att fold() kallar faktiskt foldLeft() internt.

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

fold() , foldLeft() och foldRight() kommer att returnera ett värde som har samma typ med det initiala värdet det tar. Till skillnad från foldLeft() och foldRight() kan emellertid det initiala värdet som ges till fold() endast vara av samma typ eller en supertyp av samlingen.

I det här exemplet är ordningen inte relevant, så du kan ändra fold() till foldLeft() eller foldRight() så blir resultatet detsamma. Om du använder en funktion som är känslig för ordning kommer resultatet att förändras.

Om du är osäker, föredrar foldLeft() framför foldRight() . foldRight() är mindre performant.

För varje

foreach är ovanligt bland samlingarna iteratorer i och med att det inte ger ett resultat. Istället tillämpar det en funktion på varje element som endast har biverkningar. Till exempel:

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

scala> x.foreach { println }
1
2
3

Funktionen som tillhandahålls för foreach kan ha valfri foreach , men resultatet kommer att kasseras . Vanligtvis används foreach när biverkningar är önskvärda. Om du vill omvandla data kan du överväga att använda map , filter , en for comprehension eller ett annat alternativ.

Exempel på kassering av resultat

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

Minska

reduceLeft() reduce() , reduceLeft() och reduceRight liknar veck. Funktionen som ges för att minska tar två värden och ger en tredje. När du arbetar på en lista är de två första värdena de två första värdena i listan. Resultatet av funktionen och nästa värde i listan appliceras sedan igen på funktionen, vilket ger ett nytt resultat. Detta nya resultat tillämpas med nästa värde på listan och så vidare tills det inte finns fler element. Det slutliga resultatet returneras.

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

Det finns vissa skillnader i hur reduceringsfunktionerna fungerar jämfört med vikfunktionerna. Dom är:

  1. Minskningsfunktionerna har inget initialt ackumuleringsvärde.
  2. Minska funktioner kan inte kallas på tomma listor.
  3. Minska funktioner kan bara returnera listans typ eller supertyp.


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow