Zoeken…


Sorteer een lijst

Als we de volgende lijst veronderstellen, kunnen we op verschillende manieren sorteren.

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

Het standaardgedrag van math.Ordering sorted() is het gebruik van math.Ordering , wat voor strings resulteert in een lexografische sortering:

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

sortWith kunt u uw eigen bestelling sortWith met een vergelijkingsfunctie:

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

sortBy kunt u een transformatiefunctie bieden:

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

U kunt een lijst of een gesorteerde lijst altijd omdraaien met `reverse:

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

Lijsten kunnen ook worden gesorteerd met behulp van de Java-methode java.util.Arrays.sort en de Scala wrapper scala.util.Sorting.quickSort

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

Deze methoden kunnen de prestaties verbeteren bij het sorteren van grotere collecties als de collectieconversies en unboxing / boxing kunnen worden vermeden. Lees Scala Collection sort, sortWith en sortBy Performance voor meer informatie over de prestatieverschillen.

Maak een lijst met n exemplaren van x

Een collectie maken n kopieën van een voorwerp x Gebruik de vulling methode. In dit voorbeeld wordt een List , maar dit kan werken met andere collecties waarvoor fill zinvol is:

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

Lijst en Vector Cheatsheet

Het is nu een best practice om Vector plaats van List omdat de implementaties betere prestaties hebben. Prestatiekenmerken zijn hier te vinden . Vector kan overal worden gebruikt waar List wordt gebruikt.

Lijst maken

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

Neem 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

Elementen voorafgaan

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

Voeg elementen toe

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

Deelnemen aan (samengevoegde) lijsten

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)

Gemeenschappelijke operaties

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"

Cheatsheet voor kaartenverzameling

Merk op dat deze deals met de oprichting van een verzameling van het type Map , die zich onderscheidt van de map methode.

Kaart maken

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

Een kaart kan voor de meeste bewerkingen worden beschouwd als een verzameling tuples , waarbij het eerste element de sleutel is en het tweede de waarde.

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

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

Element (en) toevoegen

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)

Gemeenschappelijke operaties

Bij bewerkingen waarbij een iteratie over een kaart plaatsvindt ( map , find , forEach , enz.), forEach de elementen van de verzameling tuples . De functieparameter kan de tuple-accessors ( _1 , _2 ) of een gedeeltelijke functie met een casusblok gebruiken:

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

Kaart en filter over een verzameling

Kaart

'Mapping' over een collectie maakt gebruik van de map functie om elk element van die collectie te transformeren in een vergelijkbare manier. De algemene syntaxis is:

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

U kunt een anonieme functie bieden:

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

Vermenigvuldigen met gehele getallen met twee

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

Filter

filter wordt gebruikt wanneer u bepaalde elementen van een verzameling wilt uitsluiten of 'filteren'. Net als bij map heeft de algemene syntaxis een functie, maar die functie moet een Boolean retourneren:

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

U kunt rechtstreeks een anonieme functie bieden:

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

Paarnummers controleren

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)

Meer kaart- en filtervoorbeelden

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 )

Inleiding tot Scala-collecties

Het Scala Collections-raamwerk is volgens de auteurs ontworpen om gemakkelijk te gebruiken, beknopt, veilig, snel en universeel te zijn.

Het raamwerk bestaat uit Scala- eigenschappen die zijn ontworpen als bouwstenen voor het maken van collecties. Lees het officiële Scala-collectiesoverzicht voor meer informatie over deze bouwstenen.

Deze ingebouwde collecties zijn gescheiden in de onveranderlijke en veranderlijke pakketten. Standaard worden de onveranderlijke versies gebruikt. Een List() samenstellen List() (zonder iets te importeren) zal een onveranderlijke lijst samenstellen.

Een van de krachtigste functies van het framework is de consistente en gemakkelijk te gebruiken interface in gelijkgestemde collecties. Het optellen van alle elementen in een verzameling is bijvoorbeeld hetzelfde voor Lijsten, Sets, Vectoren, Seqs en 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

Deze gelijkgestemde types erven van de Traversable eigenschap.

Het is nu een best practice om Vector plaats van List omdat de implementaties betere prestaties hebben. Prestatiekenmerken zijn hier te vinden . Vector kan overal worden gebruikt waar List wordt gebruikt.

Traversable types

Collection klassen die het hebben Traversable eigenschap implementeren foreach en erven vele methoden voor het uitvoeren van algemene handelingen voor collecties, die alle werken op dezelfde wijze. De meest voorkomende bewerkingen worden hier vermeld:

  • Map - map , flatMap en collect produceren nieuwe collecties door een functie toe te passen op elk element in de originele collectie.
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")
  • Conversies - toList , toArray en vele andere conversiebewerkingen veranderen de huidige collectie in een meer specifiek soort collectie. Dit zijn meestal methoden voorafgegaan door 'naar' en het meer specifieke type (dat wil zeggen 'naarLijst' converteert naar een List ).
val array: Array[Int] = List[Int](1, 2, 3).toArray // convert list of ints to array of ints
  • Grootte-informatie - is isEmpty , niet nonEmpty , size en hasDefiniteSize zijn allemaal metagegevens over de set. Dit maakt voorwaardelijke bewerkingen op de verzameling mogelijk, of voor code om de grootte van de verzameling te bepalen, inclusief of deze oneindig of discreet is.
List().isEmpty // true
List(1).nonEmpty // true
  • Element retrieval - head , last , find , en hun Option varianten worden gebruikt om de eerste of laatste element op te halen, of zoek een specifiek element in de collectie.
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))
  • Element testen - exists , forall en count worden operaties gebruikt om deze collectie te controleren of het voldoet aan een predikaat te zien.
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

Vouwen

De fold Werkwijze doorloopt een verzameling met behulp van een initiële accumulatorwaarde en toepassen van een functie die ieder element gebruikt om de accumulator succesvol werken:

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

In het bovenstaande voorbeeld werd een anonieme functie geleverd om te fold() . U kunt ook een benoemde functie gebruiken waarvoor twee argumenten nodig zijn. Met dit in mijn, kan het bovenstaande voorbeeld als volgt worden herschreven:

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

Het wijzigen van de beginwaarde heeft invloed op het resultaat:

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

De fold methode heeft twee varianten - foldLeft en foldRight .

foldLeft() van links naar rechts foldLeft() van het eerste element van de verzameling tot het laatste in die volgorde). foldRight() itereert van rechts naar links (van het laatste element naar het eerste element). fold() itereert van links naar rechts zoals foldLeft() . In feite roept fold() feite intern foldLeft() .

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

fold() , foldLeft() en foldRight() retourneren een waarde van hetzelfde type met de initiële waarde die nodig is. Anders dan foldLeft() en foldRight() , kan de initiële waarde die aan fold() echter alleen van hetzelfde type of een supertype van het type van de verzameling zijn.

In dit voorbeeld is de volgorde niet relevant, dus u kunt fold() in foldLeft() of foldRight() en het resultaat blijft hetzelfde. Het gebruik van een functie die gevoelig is voor bestelling zal de resultaten veranderen.

Geef bij twijfel de voorkeur aan foldLeft() boven foldRight() . foldRight() is minder performant.

foreach

foreach is ongebruikelijk onder de iterators van collecties omdat het geen resultaat oplevert. In plaats daarvan past het een functie toe op elk element dat alleen bijwerkingen heeft. Bijvoorbeeld:

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

scala> x.foreach { println }
1
2
3

De functie die aan foreach geleverd, kan elk foreach hebben, maar het resultaat wordt genegeerd . Meestal wordt foreach gebruikt wanneer bijwerkingen wenselijk zijn. Als u gegevens wilt transformeren, kunt u overwegen om map , filter , een for comprehension of een andere optie te gebruiken.

Voorbeeld van weggooien van resultaten

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

Verminderen

De methoden reduce() , reduceLeft() en reduceRight zijn vergelijkbaar met vouwen. De functie die is doorgegeven om te verkleinen, heeft twee waarden en levert een derde op. Wanneer u in een lijst werkt, zijn de eerste twee waarden de eerste twee waarden in de lijst. Het resultaat van de functie en de volgende waarde in de lijst worden vervolgens opnieuw toegepast op de functie, wat een nieuw resultaat oplevert. Dit nieuwe resultaat wordt toegepast met de volgende waarde van de lijst enzovoort totdat er geen elementen meer zijn. Het eindresultaat is terug.

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

Er zijn enkele verschillen in hoe de verkleiningsfuncties werken in vergelijking met de vouwfuncties. Zij zijn:

  1. De verkleiningsfuncties hebben geen initiële accumulatiewaarde.
  2. Beperkingsfuncties kunnen niet worden opgeroepen in lege lijsten.
  3. Met functies verkleinen kunt u alleen het type of het supertype van de lijst retourneren.


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow