Поиск…


Сортировка списка

Предполагая следующий список, мы можем сортировать различные способы.

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

Поведение по умолчанию sorted() заключается в использовании math.Ordering , что для строк результатов в lexographic рода:

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

sortWith позволяет вам предоставить собственный заказ, используя функцию сравнения:

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

sortBy позволяет вам предоставить функцию преобразования:

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

Вы всегда можете изменить список или отсортированный список, используя `reverse:

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

Списки также могут быть отсортированы с использованием Java-метода java.util.Arrays.sort и его оболочки Scala scala.util.Sorting.quickSort

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

Эти методы могут повысить производительность при сортировке больших коллекций, если можно избежать конверсий коллекции и распаковки / бокса. Для более подробного обсуждения различий в производительности читайте о сортировке Scala Collection, sortWith и sortBy Performance .

Создайте список, содержащий n копий x

Чтобы создать коллекцию n копий некоторого объекта x , используйте метод fill . В этом примере создается List , но он может работать с другими коллекциями, для которых fill имеет смысл:

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

Список и векторный чарт

В настоящее время лучше использовать Vector вместо List потому что реализации имеют лучшую производительность. Характеристики производительности можно найти здесь . Vector можно использовать везде, где используется List .

Создание списка

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

Возьмите элемент

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

Предварительные элементы

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

Добавить элементы

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

Присоединиться (объединить) списки

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)

Общие операции

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

Обратите внимание, что это связано с созданием набора типов Map , который отличается от метода map .

Создание карты

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

Карту можно рассматривать как набор tuples для большинства операций, где первым элементом является ключ, а второй - значение.

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

Получить элемент

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)

Добавить элемент (ы)

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)

Общие операции

В операциях, где происходит итерация по карте ( map , find , forEach и т. Д.), Элементами коллекции являются tuples . Параметр функции может либо использовать аксессоры кортежа ( _1 , _2 ), либо частичную функцию с блоком корпуса:

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

Карта и фильтр по коллекции

карта

«Сопоставление» по коллекции использует функцию map для преобразования каждого элемента этой коллекции аналогичным образом. Общий синтаксис:

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

Вы можете предоставить анонимную функцию:

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

Умножение целых чисел на два

// 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 используется, когда вы хотите исключить или «отфильтровать» определенные элементы коллекции. Как и в случае с map , общий синтаксис принимает функцию, но эта функция должна возвращать Boolean :

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

Вы можете предоставить анонимную функцию напрямую:

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

Проверка номеров пар

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)

Дополнительные примеры карт и фильтров

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 )

Введение в коллекции Scala

Рамка Scala Collections, по словам ее авторов , предназначена для простой в использовании, кратким, безопасным, быстрым и универсальным.

Структура состоит из черт Scala, которые предназначены для создания блоков для создания коллекций. Для получения дополнительной информации об этих строительных блоках ознакомьтесь с официальным обзором коллекций Scala .

Эти встроенные коллекции разделяются на неизменяемые и изменяемые пакеты. По умолчанию используются неизменяемые версии. Построение List() (без импорта чего-либо) приведет к созданию неизменяемого списка.

Одной из самых мощных функций платформы является последовательный и простой в использовании интерфейс в коллекциях с единомышленниками. Например, суммирование всех элементов в коллекции одинаково для списков, наборов, векторов, секций и массивов:

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

Эти единомышленники наследуют свойство Traversable .

В настоящее время лучше использовать Vector вместо List потому что реализации имеют лучшую производительность. Характеристики производительности можно найти здесь . Vector можно использовать везде, где используется List .

Трассируемые типы

Классы коллекции, которые имеют свойство Traversable trait foreach и наследуют множество методов для выполнения общих операций с коллекциями, которые все одинаково функционируют. Наиболее распространенные операции перечислены здесь:

  • Map - map , flatMap и collect новые коллекции, применяя функцию к каждому элементу в исходной коллекции.
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")
  • Конверсии - toList , toArray и многие другие операции преобразования меняют текущую коллекцию на более конкретный вид коллекции. Обычно это методы с добавлением «to» и более конкретный тип (т.е. «toList» преобразуется в List ).
val array: Array[Int] = List[Int](1, 2, 3).toArray // convert list of ints to array of ints
  • Информация о размере - isEmpty , nonEmpty , size и hasDefiniteSize - это все метаданные о наборе. Это позволяет использовать условные операции в коллекции или для определения размера коллекции, включая ее бесконечность или дискретность.
List().isEmpty // true
List(1).nonEmpty // true
  • Поиск элемента - head , в last , find , и их Option варианты используются для получения первого или последнего элемента, или найти определенный элемент в коллекции.
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))
  • Тесты элементов - exists , forall и count - это операции, используемые для проверки этой коллекции, чтобы увидеть, удовлетворяет ли она предикату.
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

складка

Метод fold выполняет итерацию по коллекции, используя начальное значение аккумулятора и применяя функцию, которая использует каждый элемент для успешного обновления накопителя:

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

В приведенном выше примере анонимная функция была отправлена ​​в fold() . Вы также можете использовать именованную функцию, которая принимает два аргумента. Принимая это в моем, приведенный выше пример можно переписать следующим образом:

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

Изменение начального значения повлияет на результат:

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

fold метод имеет два варианта - foldLeft и foldRight .

foldLeft() выполняет foldLeft() слева направо (от первого элемента коллекции до последнего в этом порядке). foldRight() выполняет итерацию справа налево (от последнего элемента до первого элемента). fold() выполняет foldLeft() слева направо, например foldLeft() . Фактически, fold() фактически вызывает foldLeft() внутри.

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

fold() , foldLeft() и foldRight() возвращают значение, имеющее тот же тип, с начальным значением, которое требуется. Однако, в отличие от foldLeft() и foldRight() , начальное значение, данное fold() может быть только одного типа или супертипа типа коллекции.

В этом примере порядок не имеет значения, поэтому вы можете изменить fold() на foldLeft() или foldRight() и результат останется таким же. Использование функции, чувствительной к порядку, изменит результаты.

Если есть сомнения, предпочитайте foldLeft() над foldRight() . foldRight() менее результативен.

Для каждого

foreach необычен среди итераторов коллекций тем, что он не возвращает результат. Вместо этого он применяет функцию к каждому элементу, который имеет только побочные эффекты. Например:

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

scala> x.foreach { println }
1
2
3

Функция, предоставленная foreach может иметь любой тип возврата, но результат будет отброшен . Обычно foreach используется, когда желательны побочные эффекты. Если вы хотите преобразовать данные, используйте map , filter , for comprehension или другой вариант.

Пример отбрасывания результатов

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

уменьшить

reduceLeft() reduce() , reduceLeft() и reduceRight похожи на складки. Функция, переданная для уменьшения, принимает два значения и дает третью. При работе в списке первые два значения являются первыми двумя значениями в списке. Результат функции и следующее значение в списке затем повторно применяются к функции, что дает новый результат. Этот новый результат применяется со следующим значением списка и так далее, пока не будет больше элементов. Окончательный результат возвращается.

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

Существуют некоторые различия в том, как работают функции сокращения по сравнению с функциями fold. Они есть:

  1. Функции уменьшения не имеют начального значения аккумулятора.
  2. Сокращение функций нельзя вызывать в пустых списках.
  3. Функции сокращения могут возвращать только тип или супертип списка.


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow