Szukaj…


Sortuj listę

Zakładając poniższą listę , możemy posortować różne sposoby.

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

Domyślne zachowanie sorted() polega na użyciu math.Ordering , które dla łańcuchów powoduje sortowanie leksykalne :

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

sortWith pozwala na zapewnienie własnego zamówienia z wykorzystaniem funkcji porównania:

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

sortBy pozwala na zapewnienie funkcji transformacji:

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

Zawsze możesz odwrócić listę lub listę posortowaną, używając `reverse:

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

Listy można również sortować przy użyciu metody Java java.util.Arrays.sort i jej opakowania Scala scala.util.Sorting.quickSort

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

Te metody mogą poprawić wydajność podczas sortowania większych kolekcji, jeśli można uniknąć konwersji kolekcji i rozpakowywania / boksu. Aby uzyskać bardziej szczegółową dyskusję na temat różnic w wydajności, przeczytaj o sortowaniu Scala Collection, sortWith i sortBy Performance .

Utwórz listę zawierającą n kopii x

Aby utworzyć kolekcję n kopii jakiegoś obiektu x , użyj metody fill . W tym przykładzie tworzona jest List , ale może ona działać z innymi kolekcjami, dla których fill ma sens:

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

Lista i wektor Cheatheet

Najlepszą praktyką jest teraz stosowanie Vector zamiast List ponieważ implementacje mają lepszą wydajność. Charakterystykę wydajności można znaleźć tutaj . Vector można stosować wszędzie tam, gdzie używana jest List .

Tworzenie listy

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

Weź 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

Przygotuj elementy

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

Dołącz elementy

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

Dołącz (konkatenuj) listy

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)

Wspólne operacje

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"

Arkusz kolekcji map

Zauważ, że dotyczy to tworzenia kolekcji typu Map , która różni się od metody map .

Tworzenie mapy

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

Mapę można uznać za zbiór tuples dla większości operacji, gdzie pierwszy element jest kluczem, a drugi wartością.

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

Zdobądź 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)

Dodaj element (y)

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)

Wspólne operacje

W operacjach, w których występuje iteracja nad mapą ( map , find , forEach itp.), Elementami kolekcji są tuples . W parametrze funkcji można użyć krotek ( _1 , _2 ) lub funkcji częściowej z blokiem obserwacji:

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

Mapuj i filtruj kolekcję

Mapa

„Mapowanie” w kolekcji wykorzystuje funkcję map do transformacji każdego elementu tej kolekcji w podobny sposób. Ogólna składnia to:

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

Możesz zapewnić anonimową funkcję:

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

Mnożenie liczb całkowitych przez dwa

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

Filtr

filter jest używany, gdy chcesz wykluczyć lub „odfiltrować” niektóre elementy kolekcji. Podobnie jak w przypadku map , ogólna składnia przyjmuje funkcję, ale ta funkcja musi zwrócić wartość Boolean :

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

Możesz zapewnić anonimową funkcję bezpośrednio:

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

Sprawdzanie numerów par

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)

Więcej przykładów map i filtrów

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 )

Wprowadzenie do kolekcji Scala

Ramy kolekcji Scala, według jej autorów , zostały zaprojektowane tak, aby były łatwe w użyciu, zwięzłe, bezpieczne, szybkie i uniwersalne.

Struktura składa się z cech Scali , które zostały zaprojektowane jako elementy składowe do tworzenia kolekcji. Aby uzyskać więcej informacji na temat tych elementów, przeczytaj oficjalny przegląd kolekcji Scala .

Te wbudowane kolekcje są podzielone na niezmienne i zmienne pakiety. Domyślnie używane są niezmienne wersje. Konstruowanie List() (bez importowania czegokolwiek) spowoduje utworzenie niezmiennej listy.

Jedną z najpotężniejszych funkcji frameworka jest spójny i łatwy w użyciu interfejs w kolekcjach o podobnych poglądach. Na przykład sumowanie wszystkich elementów w kolekcji jest takie samo dla list, zestawów, wektorów, sekwencji i tablic:

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

Te podobnie myślące typy dziedziczą od cechy Traversable .

Najlepszą praktyką jest teraz stosowanie Vector zamiast List ponieważ implementacje mają lepszą wydajność. Charakterystykę wydajności można znaleźć tutaj . Vector można stosować wszędzie tam, gdzie używana jest List .

Typy przejezdne

Klasy kolekcji posiadające cechę Traversable implementują foreach i dziedziczą wiele metod wykonywania wspólnych operacji na kolekcjach, które wszystkie działają identycznie. Najczęstsze operacje są wymienione tutaj:

  • Map - map , flatMap i collect produkować nowe kolekcje, stosując funkcję do każdego elementu w oryginalnej kolekcji.
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")
  • Konwersje - toList , toArray i wiele innych operacji konwersji zmieniają bieżącą kolekcję w bardziej konkretny rodzaj kolekcji. Są to zwykle metody poprzedzone znakiem „do”, a bardziej szczegółowy typ (tzn. „ToList” konwertuje na List ).
val array: Array[Int] = List[Int](1, 2, 3).toArray // convert list of ints to array of ints
  • Informacje o rozmiarze - isEmpty , nonEmpty , size i hasDefiniteSize to metadane dotyczące zestawu. Umożliwia to warunkowe operacje na kolekcji lub kod określający rozmiar kolekcji, w tym jej nieskończoność lub dyskretność.
List().isEmpty // true
List(1).nonEmpty // true
  • Pobieranie elementu - head , last , find i ich warianty Option służą do pobierania pierwszego lub ostatniego elementu lub znajdowania określonego elementu w kolekcji.
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)
  • Operacje partition - partition , partition splitAt , span i groupBy podział bieżącej kolekcji na różne części.
// split numbers into < 0 and >= 0
List(-2, -1, 0, 1, 2).partition(num => num < 0) // = (List(-2, -1), List(0, 1, 2))
  • Testy elementów - exists , forall i count są operacjami używanymi do sprawdzenia tej kolekcji, aby sprawdzić, czy spełnia predykat.
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

Zagięcie

Metoda fold iteruje kolekcję, wykorzystując początkową wartość akumulatora i stosując funkcję, która używa każdego elementu do pomyślnej aktualizacji akumulatora:

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

W powyższym przykładzie dostarczono anonimową funkcję fold() . Możesz także użyć nazwanej funkcji, która pobiera dwa argumenty. Biorąc to pod uwagę, powyższy przykład można przepisać w następujący sposób:

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

Zmiana wartości początkowej wpłynie na wynik:

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

Metoda fold ma dwa warianty - foldLeft i foldRight .

foldLeft() od lewej do prawej (od pierwszego elementu kolekcji do ostatniego w tej kolejności). foldRight() iteracji od prawej do lewej (od ostatniego elementu do pierwszego elementu). fold() iteruje od lewej do prawej jak foldLeft() . W rzeczywistości fold() faktycznie wywołuje foldLeft() wewnętrznie.

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

fold() , foldLeft() i foldRight() zwracają wartość tego samego typu z wartością początkową, którą przyjmuje. Jednak, w przeciwieństwie do foldLeft() i foldRight() , wartość początkowa podana dla fold() może być tylko tego samego typu lub nadtypu typu kolekcji.

W tym przykładzie kolejność nie jest istotna, więc możesz zmienić fold() na foldLeft() lub foldRight() a wynik pozostanie taki sam. Użycie funkcji wrażliwej na porządek zmieni wyniki.

W razie wątpliwości wybierz foldLeft() foldRight() . foldRight() jest mniej wydajny.

Dla każdego

foreach jest niezwykły wśród iteratorów kolekcji, ponieważ nie zwraca wyniku. Zamiast tego stosuje funkcję do każdego elementu, który ma tylko skutki uboczne. Na przykład:

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

scala> x.foreach { println }
1
2
3

Funkcja dostarczona do foreach może mieć dowolny typ zwracany, ale wynik zostanie odrzucony . Zazwyczaj foreach stosuje się, gdy pożądane są działania niepożądane. Jeśli chcesz przekształcić dane, rozważ użycie map , filter , for comprehension lub innej opcji.

Przykład odrzucania wyników

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

Redukować

Metody reduce() , reduce() reduceLeft() i reduceRight są podobne do reduceRight . Funkcja przekazana do zmniejszenia przyjmuje dwie wartości i daje trzecią. Podczas pracy na liście pierwsze dwie wartości są pierwszymi dwiema wartościami na liście. Wynik funkcji i następna wartość na liście są następnie ponownie stosowane do funkcji, co daje nowy wynik. Ten nowy wynik jest stosowany z następną wartością listy i tak dalej, aż nie będzie już żadnych elementów. Ostateczny wynik jest zwracany.

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

Istnieją pewne różnice w działaniu funkcji zmniejszania w porównaniu do funkcji składania. Oni są:

  1. Funkcje redukcji nie mają początkowej wartości akumulatora.
  2. Funkcji ograniczania nie można wywoływać na pustych listach.
  3. Funkcje zmniejszania mogą zwracać tylko typ lub nadtyp listy.


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow