List
List представляет собой линейную неизменяемую последовательность. Каждый раз, когда в список добавляются или удаляются элементы, по сути создается новый список из существующего.
Он обеспечивает быстрый (за постоянное время) доступ как к первому элементу, так и к остальному списку, а также быструю операцию добавления нового элемента в начало списка. Большинство оставшихся операции занимают линейное время исполнения.
Создание списка
Список можно создать различными способами:
val ints = List(1, 2, 3)
// ints: List[Int] = List(1, 2, 3)
val names = List("Joel", "Chris", "Ed")
// names: List[String] = List("Joel", "Chris", "Ed")
val namesAgain = "Joel" :: "Chris" :: "Ed" :: Nil
// namesAgain: List[String] = List("Joel", "Chris", "Ed")
При желании тип списка можно объявить, хотя обычно в этом нет необходимости:
val ints: List[Int] = List(1, 2, 3)
// ints: List[Int] = List(1, 2, 3)
val names: List[String] = List("Joel", "Chris", "Ed")
// names: List[String] = List("Joel", "Chris", "Ed")
Одно исключение — когда в коллекции смешанные типы; в этом случае тип желательно указывать явно:
val things: List[Any] = List(1, "two", 3.0)
// things: List[Any] = List(1, "two", 3.0)
Добавление элементов в список
Поскольку список неизменяем, в него нельзя добавлять новые элементы. Вместо этого создается новый список с добавленными к существующему списку элементами. Например, учитывая этот список:
val a = List(1, 2, 3)
Для добавления одного элемента используется метод ::
, для добавления нескольких — :::
, как показано здесь:
val b = 0 :: a
// b: List[Int] = List(0, 1, 2, 3)
val c = List(-1, 0) ::: a
// c: List[Int] = List(-1, 0, 1, 2, 3)
Также можно добавить элементы в конец списка, но, поскольку список является односвязным, следует добавлять к нему элементы только в начало; добавление элементов в конец списка — относительно медленная операция, особенно при работе с большими последовательностями.
Если необходимо добавлять к неизменяемой последовательности элементы в начало и конец, используйте Vector
.
Поскольку List
является связанным списком,
крайне нежелательно пытаться получить доступ к элементам больших списков по значению их индекса.
Например, если есть List
с миллионом элементов, доступ к такому элементу, как myList(999_999)
,
займет относительно много времени, потому что этот запрос должен пройти почти через все элементы.
Если есть большая коллекция и необходимо получать доступ к элементам по их индексу,
вместо List
используйте Vector
или ArrayBuffer
.
Как запомнить названия методов
В методах Scala символ :
представляет сторону, на которой находится последовательность,
поэтому, когда используется метод +:
, список нужно указывать справа:
0 +: a
// res1: List[Int] = List(0, 1, 2, 3)
Аналогично, если используется :+
, список должен быть слева:
a :+ 4
// res2: List[Int] = List(1, 2, 3, 4)
Кроме того, хорошей особенностью этих символических имен методов является то, что они стандартизированы.
Те же имена методов используются с другими неизменяемыми последовательностями, такими как Seq
и Vector
.
Также можно использовать несимволические имена методов для добавления элементов
в начало (a.prepended(4)
) или конец (a.appended(4)
).
Как пройтись по списку
Представим, что есть список имён:
val names = List("Joel", "Chris", "Ed")
Напечатать каждое имя можно следующим способом:
for name <- names do println(name)
// Joel
// Chris
// Ed
Преимуществом использования циклов for
с коллекциями заключается в том, что Scala стандартизирован,
и один и тот же подход работает со всеми последовательностями,
включая Array
, ArrayBuffer
, List
, Seq
, Vector
, Map
, Set
и т. д.
Немного истории
Список Scala подобен списку из языка программирования Lisp, который был впервые представлен в 1958 году. Действительно, в дополнение к привычному способу создания списка:
val ints = List(1, 2, 3)
// ints: List[Int] = List(1, 2, 3)
точно такой же список можно создать следующим образом:
val list = 1 :: 2 :: 3 :: Nil
// list: List[Int] = List(1, 2, 3)
Это работает, потому что List
— односвязный список, оканчивающийся элементом Nil
,
а ::
— это метод List
, работающий как оператор "cons" в Lisp.
Ссылки: