Clojure'da, bir liste üzerinde bir vektörü ne zaman kullanmalıyım ve tam tersi?


Yanıtlar:


113

Bir kez daha, sabırsızlanarak ve Freenode'daki #clojure'da sorarak kendi sorumu yanıtlamış gibi görünüyor. Stackoverflow.com'da kendi sorularınızı yanıtlamanız teşvik edilir: D

Rich Hickey ile hızlı bir tartışma yaptım ve işte işin özü.

[12:21] <Raynes>    Vectors aren't seqs, right?
[12:21] <rhickey>   Raynes: no, but they are sequential
[12:21] <rhickey>   ,(sequential? [1 2 3])
[12:21] <clojurebot>    true
[12:22] <Raynes>    When would you want to use a list over a vector?
[12:22] <rhickey>   when generating code, when generating back-to-front
[12:23] <rhickey>   not too often in Clojure

Serbest moddayken karanlık tarafa gelin ve #stackoverflow'a katılın! :-P
Chris Jester-Young

Aslında orada boş dururdum. IRC istemcilerini değiştirdim ve otomatik katılma listeme #stackoverflow eklemeyi hiç düşünmedim.
Rayne

Ben bir Lisp acemisiyim, ancak vektörlerin, haritaların ve kümelerin tüm kodun verilerle değiştirilebilir olduğu fikrini bir şekilde bozup bozmadığını merak ettim. Yoksa bu Clojure'u pratik bir Lisp yapan şeylerden biri mi? (YA DA, bir vektörü değerlendirebilir misin?)
Rob Grant

26
Bu tamamen yardımcı olmayan bir sohbet pasajıdır. "Kod üretme" "arkadan öne üretme" -> tam olarak mı? Bu soruyla gerçekten zorlanıyorum çünkü kitabımda tembellik + bildirici stil = çok daha iyi performans ve yine de Clojure'de her yerde vektörler öneriliyor ve bu da kafamı karıştırıyor.
Jimmy Hoffa

22
@JimmyHoffa Anladığım kadarıyla: "Kod Oluşturma" = "Makro İçinde" (çünkü kodun çoğu işlev çağrılarıdır, dolayısıyla listeler); "arkadan öne oluşturma" = "başa ekleyerek bir sıra oluşturma".
omiel

89

Java programlamayı çok yaptıysanız ve Java toplama çerçevesine aşina iseniz, gibi listeler LinkedListve ArrayList. Yani neredeyse aynı şekilde kapları seçebilirsiniz.

Daha fazla açıklama için: Öğeleri tek tek dizinin önüne veya arkasına çok fazla eklemeyi düşünüyorsanız, bağlantılı bir liste vektörden çok daha iyidir çünkü öğelerin her seferinde karıştırılmasına gerek yoktur. Ancak, belirli öğelere (listenin önüne veya arkasına yakın değil) sık sık (yani rastgele erişim) ulaşmak istiyorsanız, vektörü kullanmak isteyeceksiniz.

Bu arada, vektörler kolayca sıralı hale getirilebilir.

user=> (def v (vector 1 2 3))
#'user/v
user=> v
[1 2 3]
user=> (seq v)
(1 2 3)
user=> (rseq v)
(3 2 1)

Vektörler sıralı değildir, ancak sıralıdırlar. (kaynak: Rich, freenode üzerinde #clojure'da.) Ayrıca Java'yı gerçekten bilmiyorum, ama Rich sorumu cevapladı.
Rayne

1
Gönderimi, vektörlerin seq işlevi aracılığıyla sıralı hale getirilebileceğini söylemek için düzenleyeceğim . :-)
Chris Jester-Young

2
Cevabınızı seçtim çünkü soruyu gerçekten cevapladı ve kendi cevaplarımı doğru olarak seçmekten gerçekten hoşlanmıyorum. Doğru görünmüyor. Teşekkürler. :)
Rayne

Birinci ve sonuncunun eklenmesi durumunda bir deque, bağlantılı bir listeden daha iyidir. LL'ler oldukça berbat: P
kutulu

1
@boxed Bir vektörün üstüne bir deque uygulayamazsınız veya kendinizi ArrayListetkili bir şekilde yeniden uygulayamazsınız ArrayDeque.
Chris Jester-Young

44

Vektörlerin O (1) rastgele erişim süreleri vardır, ancak önceden tahsis edilmeleri gerekir. Listeler dinamik olarak genişletilebilir, ancak rastgele bir öğeye erişim O (n) 'dur.


3
Teknik olarak, bağlantılı listelerin O (1) erişim süreleri vardır ... yalnızca ön veya arka öğeye erişiyorsanız. :-P Bununla birlikte, vektörlerin O (1) rasgele erişimi vardır. :-)
Chris Jester-Young

4
(Yukarıda açıklandığı gibi "bağlantılı liste" çift bağlantılı listeleri ifade eder. Tekil bağlantılı listelerin yalnızca ön öğeye O (1) erişimi vardır. :-P)
Chris Jester-Young

1
Birisi Clojure'e yeni daldığı için, bu daha fazla oy alan diğer ikisinden ÇOK daha iyi bir cevaptır. Diğer ikisi bana faydası yok.
keithjgrant

@ ChrisJester-Young Tek bağlantılı liste, arka öğeye bir referans saklarsa, arkaya O (1) erişimini destekleyebilir, bunun gibi .
Gill Bates

30

Bir vektör ne zaman kullanılır:

  • Dizine alınmış erişim performansı - Dizine alınmış erişim için ~ O (1) maliyet, listeler için ise O (n) alırsınız
  • Eklenen - bağlaç ile ~ O (1)
  • Uygun gösterim - Ben yazmayı ve [1 2 3] 'ü okumayı' (1 2 3) 'den daha kolay buluyorum, her ikisinin de işe yarayacağı durumlarda.

Liste ne zaman kullanılır:

  • Buna bir sıra olarak erişmek istediğinizde (listeler, yeni nesneler tahsis etmek zorunda kalmadan doğrudan sırayı desteklediğinden)
  • Prepending - Eksileri olan bir listenin başına ekleme veya tercihen con, O (1)

3
Her iki uca da eklerken / çıkarırken bile bir liste oldukça kötü bir seçimdir. Deque çok daha iyidir (CPU'da ve özellikle bellekte). Github.com/pjstadig/deque-clojure'u
kutulu

2
Re: the ~O(1), bu maliyet açıklamasının yardımcı olabileceği kişiler için - stackoverflow.com/questions/200384/constant-amortized-time
Merlyn Morgan-Graham

13

kısa bir yan not:

"Vektörlerin sıralı olmadığını, Listelerin olduğunu okudum." 

diziler, listelerden veya vektörlerden (veya haritalardan veya kümelerden) daha geneldir. REPL'in listeleri ve dizileri aynı şekilde yazdırması
talihsiz bir durumdur çünkü gerçekten farklı olsalar bile listelerin dizilermiş gibi görünmesini sağlar. (seq) işlevi, listeler de dahil olmak üzere birçok farklı şeyden bir dizi oluşturur ve daha sonra bu diziyi, sıra ile şık şeyler yapan çok sayıda işlevden herhangi birine besleyebilirsiniz.

user> (class (list 1 2 3))
clojure.lang.PersistentList

user> (class (seq (list 1 2 3)))
clojure.lang.PersistentList

user> (class (seq [1 2 3]))
clojure.lang.PersistentVector$ChunkedSeq

Sec, zaten bir seq ise argümanını döndüren bir kısayol içerir:

user> (let [alist (list 1 2 3)] (identical? alist (seq alist)))
true
user> (identical? (list 1 2 3) (seq (list 1 2 3)))
false

static public ISeq seq(Object coll){
        if(coll instanceof ASeq)
                return (ASeq) coll;
        else if(coll instanceof LazySeq)
                return ((LazySeq) coll).seq();
        else
                return seqFrom(coll);
}

listeler dizilerdir, ancak diğer şeyler de vardır ve tüm diziler liste değildir.


Küçük bir noktayı seçmek istemiyorum, bu sadece yararlı bir şeyi belirtmek için bir fırsat. birçok kişi bunu zaten biliyor olacak :)
Arthur Ulfeldt

2
Onun classyerine mi demek istiyorsun class??
qerub

Örneğinizin clojure güncellemelerinden sonra değişip değişmediğinden emin değilim (sanırım 1.5'deyim), ancak her iki örneğiniz de clojure.lang.PersistentListbenim için geri dönüyor . Sana yazmak istedim tahmin ediyorum classdeğil class?.
Adrian Mouat

Gerçekten yaptım! Bunu düzelteceğim
Arthur Ulfeldt

Hala biraz kafası karışmış; beri classgetiri Bahsettiğiniz bu ifadelerin ikisi için de aynı PersistentList, bu diziler ve listeler aslında aynı şey olduğunu ima?
johnbakers
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.