Skalada Dizi ve Liste Arasındaki Fark


142

Hangi durumlarda Array (Buffer) ve List (Buffer) kullanmalıyım. Bildiğim tek bir fark, dizilerin değişken olmayan ve listelerin kovaryant olduğudur. Peki ya performans ve diğer bazı özellikler?

Yanıtlar:


155

Değişmez Yapılar

Scala ListEğer (muhtemelen) bir çok daha bunu kullanarak olmalıdır, Scala böyle bir temel yapısı olan değişmez bir özyinelemeli veri yapısıdır Array(aslında hangi değişken - değişmez analog ait Arrayolduğunu IndexedSeq).

Eğer bir Java arka plandan geliyorsanız ne zaman kullanılacağına, daha sonra bariz paralel LinkedListüzerinde ArrayList. Birincisi genel olarak yalnızca geçilen (ve boyutu önceden bilinmeyen) listeler için kullanılırken ikincisi, bilinen bir boyuta (veya maksimum boyuta) sahip olan veya hızlı rasgele erişimin önemli olduğu listeler için kullanılmalıdır .

Değişken Yapılar

ListBufferdaha sonra bu tür bir dönüşüm gerekiyorsa Listkullanmak için tek neden olan bir sabit zamanlı dönüşüm sağlar ListBuffer.

JVM'de Arraybir Java dizisi tarafından bir scala uygulanmalıdır ve bu nedenle bir Array[Int], a'dan çok daha fazla performans gösterebilir (an olarak int[]) List[Int](Scala'nın yeni @specializedözelliğe sahip en son sürümlerini kullanmıyorsanız, içeriğini kutlayacak ) .

Bununla birlikte, ArrayScala'da s kullanımının minimumda tutulması gerektiğini düşünüyorum, çünkü dizinizin gerçekten gerekli ilkel tip tarafından desteklenip desteklenmeyeceğine karar vermek için gerçekten kaputun altında neler olup bittiğini bilmeniz gerekiyor gibi görünüyor veya ambalaj tipi olarak kutulu olmalıdır.


ayrıca bkz. stackoverflow.com/questions/3213368/… ve stackoverflow.com/questions/2481149/… Diziler için "eşittir" tanımı, aynı diziye başvurmalarıdır
oluies

130

Daha önce gönderilen cevaplara ek olarak, bazı özellikler aşağıda verilmiştir.

A Array[A]tam anlamıyla bir Java dizisi olsa da, a (boş liste) olan veya bir çiftten oluşan List[A]değişmez bir veri yapısıdır .Nil(A, List[A])

Performans farklılıkları

                          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)

Bellek farklılıkları

                          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)

Eğer hızlı rastgele erişime gerekmedikçe Yani, elemanlarını saymak gerekir, ya da herhangi bir nedenle bir yıkıcı güncelleştirmeleri gerek Listiyi bir daha Array.


Bu İşletim Sistemi Listenin kopyalanma zamanını dikkate almalı mı? Sana böyle örn testi yapıyoruz varsayalım: list = list.drop(i). Veya, kaputun arkasında biraz sihir mi oluyor?

2
Bu, gerektiğinde listelerin ve dizilerin kopyalanmasını dikkate alır. Gibi şeylerin dropasla listenin bırakılmayan kısmını kopyalaması gerekmediğini unutmayın . Örneğin (x::xs).drop(1), xsbir "kopyası" değildir xs.
Apocalisp

6
Bu asimtotiklerin Scala ile hiçbir ilgisi yoktur. C'deki aynı veri yapısı, sabit faktörlere kadar hızlı olacaktır.
Apocalisp

1
@Apocalisp Referansınız var mı veya bu koşullar altında hangi bilgileri belirlediniz?
Phil

1
@Phil Bunlar ölçüm değil, asimtotiktir. Her koşulda doğru olacaklar.
Apocalisp

18

Bir Dizi değiştirilebilir, yani her dizinin değerlerini değiştirebilirsiniz; Liste (varsayılan olarak) değiştirilemez, yani her değişiklik yaptığınızda yeni bir liste oluşturulur. Çoğu durumda bu değişmez veri türleri ile çalışmak için daha "işlevsel" tarzıdır ve muhtemelen denemek ve benzeri yapılara sahip bir listesi kullanmalıdır yield, foreach, matchvb.

Performans karakteristikleri için, Array öğelere rastgele erişimle daha hızlı olurken, yeni öğeleri eklerken (eklerken) Liste daha hızlıdır. Onları tekrarlamak karşılaştırılabilir.


@leonm - apols, OP'nin sadece * Buffer sınıfları hakkında sorduğunu düşündüm, onların da "normal" olanları sorduğunu anladım!
oxbow_lakes

2
Bir ArrayBuffer'a eklemek genellikle bir Listenin başına (veya bir ListBuffer'a öğe eklemek) göre daha hızlıdır, çünkü listeler bir sarmalayıcı nesnesinin oluşturulmasını gerektirirken ArrayBuffer'ın nesneyi (ortalama olarak yaklaşık iki kez) yeni bir diziye kopyalaması gerekir . İki kopya genellikle bir nesne oluşturma işleminden daha hızlıdır, bu nedenle ArrayBuffer eki genellikle Liste başlangıcını geçer.
Rex Kerr

dizi iterate over, önbellek nedeniyle listeden çok daha hızlı performans gösterir
Bin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.