Різниця між масивом та списком у масштабі


142

У яких випадках я повинен використовувати масив (буфер) та список (буфер). Я знаю лише одну відмінність, що масиви є неваріантними, а списки - коваріантними. А як щодо продуктивності та деяких інших характеристик?

Відповіді:


155

Незмінні структури

Scala Listє непорушною рекурсивної структурою даних , яка є такою фундаментальною структурою в Scala, що ви повинні (можливо) будете використовувати його набагато більше , ніж Array(що насправді змінюваний - незмінний аналог з Arrayце IndexedSeq).

Якщо ви їдете з фону Java, то очевидно , паралель , коли використовувати LinkedListбільш ArrayList. Перші , як правило , використовується для списків , які тільки коли - або перетинали (і розмір яких не відомий заздалегідь) , тоді як останній повинен використовуватися для списків , які або мають відомий розмір (або максимальний розмір) або для яких швидкий довільний доступ важливо.

Змінні структури

ListBufferзабезпечує конвертацію в постійному часі, до Listякої можна скористатися лише однією причиною, ListBufferякщо потрібна така пізня конверсія.

Скала Arrayповинна бути реалізована в JVM Java-масивом, а отже, Array[Int]може бути набагато ефективнішою (як an int[]), ніж а List[Int](яка вказує її вміст, якщо ви не використовуєте найновіші версії Scala, які мають нову @specializedфункцію) .

Однак я вважаю, що використання Arrays у Scala слід звести до мінімуму, тому що вам здається, що вам справді потрібно знати, що відбувається під кришкою, щоб вирішити, чи справді ваш масив буде підкріплений необхідним примітивним типом, чи може бути в коробці як обгортковий тип.


також див. stackoverflow.com/questions/3213368/… та stackoverflow.com/questions/2481149/…, визначення "рівних" для масивів полягає в тому, що вони посилаються на той самий масив
олюї

130

Окрім вже опублікованих відповідей, ось деякі конкретики.

Хоча а - 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)

Тому, якщо вам не потрібен швидкий випадковий доступ, вам потрібно порахувати елементи, або чомусь вам потрібні деструктивні оновлення, a Listкраще, ніж an Array.


Чи повинні ці Ос розглянути час для копіювання Списку? Я припускаю , що ви робите тест , як це, наприклад: list = list.drop(i). Або: Чи виникає якась магія за капотом?

2
При цьому враховується копіювання списків та масивів при необхідності. Зауважте, що такі речі, як dropніколи, не потрібно копіювати частину списку, яка не була скинута. Наприклад, (x::xs).drop(1)це точно xs, а не "копія" xs.
Апокаліпс

6
Ці асимптотики не мають нічого спільного із Scala. Та сама структура даних у C буде точно такою ж швидкою до постійних факторів.
Апокаліпс

1
@Apocalisp Чи є у вас посилання або за яких умов ви визначили цю інформацію?
Філ

1
@Phil Це асимптотика, а не вимірювання. Вони будуть виконуватись за будь-яких умов.
Апокаліпс

18

Масив є змінним, тобто ви можете змінювати значення кожного індексу, тоді як Список (за замовчуванням) є незмінним, тобто новий список створюється кожного разу, коли ви вносите зміни. У більшості випадків це більш «функціональний» стиль роботи з незмінними типами даних , і ви , ймовірно , слід спробувати використовувати список з конструкціями , як yield, foreach, matchі так далі.

Для характеристик продуктивності масив швидший із випадковим доступом до елементів, тоді як список швидший під час попереднього (додавання) нових елементів. Ітерація над ними порівнянна.


@leonm - apols, я думав, що ОП питають виключно про * Buffer класах, я розумію, що вони також запитували про «нормальних»!
oxbow_lakes

2
Зазвичай швидше додавати ArrayBuffer, ніж додати до списку (або додати елемент до ListBuffer), оскільки списки вимагають створення об’єкта обгортки, тоді як ArrayBuffer просто повинен скопіювати об'єкт (в середньому приблизно в два рази) до нового масиву . Дві копії, як правило, швидші, ніж створення одного об'єкта, тому додавання ArrayBuffer зазвичай б'є препендент.
Рекс Керр

масив виконує набагато швидше, ніж список, коли iterate overчерез кеш
Bin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.