В каких случаях следует использовать Array (Buffer) и List (Buffer). Единственное отличие, которое я знаю, заключается в том, что массивы невариантны, а списки ковариантны. А как насчет производительности и некоторых других характеристик?
Ответы:
Scala List
является непреложной рекурсивной структурой данных , которая является такой фундаментальной структурой в Scala, что вы должны (возможно) будете использовать его гораздо больше , чем Array
(что на самом деле изменяемый - неизменен аналог из Array
это IndexedSeq
).
Если вы работаете с Java, очевидная параллель - когда использовать LinkedList
over ArrayList
. Первый обычно используется для списков, которые только когда-либо просматриваются (и размер которых не известен заранее), тогда как последний следует использовать для списков, которые либо имеют известный размер (или максимальный размер), либо для которых важен быстрый произвольный доступ .
ListBuffer
обеспечивает преобразование с постоянным временем в a, List
что является единственной причиной для использования, ListBuffer
если требуется такое более позднее преобразование.
Scala Array
должен быть реализован на JVM с помощью массива Java, и, следовательно, он Array[Int]
может быть намного более производительным (как int[]
), чем List[Int]
(который будет упаковывать его содержимое, если вы не используете самые последние версии Scala, которые имеют новую @specialized
функцию) .
Однако я думаю, что использование Array
s в Scala должно быть сведено к минимуму, потому что кажется, что вам действительно нужно знать, что происходит под капотом, чтобы решить, действительно ли ваш массив будет поддерживаться требуемым примитивным типом или может быть упакованным как тип оболочки.
В дополнение к уже опубликованным ответам, вот некоторые особенности.
В то время как an Array[A]
буквально представляет собой массив Java, a List[A]
- это неизменяемая структура данных, которая либо Nil
(пустой список), либо состоит из пары (A, List[A])
.
Различия в производительности
Array List
Access the ith element θ(1) θ(i)
Delete the ith element θ(n) θ(i)
Insert an element at i θ(n) θ(i)
Reverse θ(n) θ(n)
Concatenate (length m,n) θ(n+m) θ(n)
Count the elements θ(1) θ(n)
Различия в памяти
Array List
Get the first i elements θ(i) θ(i)
Drop the first i elements θ(n-i) θ(1)
Insert an element at i θ(n) θ(i)
Reverse θ(n) θ(n)
Concatenate (length m,n) θ(n+m) θ(n)
Поэтому, если вам не нужен быстрый произвольный доступ, нужно подсчитывать элементы или по какой-то причине вам нужны деструктивные обновления, List
лучше, чем Array
.
list = list.drop(i)
. Или, за капотом творится какая-то магия?
drop
никогда не нужно копировать часть списка, которая не была удалена. Например, (x::xs).drop(1)
это точно xs
, а не "копия" xs
.
Массив является изменяемым, что означает, что вы можете изменять значения каждого индекса, в то время как список (по умолчанию) является неизменным, что означает, что новый список создается каждый раз, когда вы вносите изменения. В большинстве случаев это более «функциональный» стиль работы с неизменяемыми типами данных , и вы , вероятно , следует попытаться использовать список с конструкциями , как yield
, foreach
, match
и так далее.
Что касается характеристик производительности, массив быстрее работает с произвольным доступом к элементам, тогда как список быстрее при добавлении (добавлении) новых элементов. Итерация по ним сопоставима.
iterate over
из-за кеширования