Liste yerine F # 'da bir dizi ne zaman kullanılır?


82

Bir listenin aslında değerler içerdiğini ve bir dizinin bunun için bir takma ad olduğunu anlıyorum IEnumerable<T>. Pratik F # geliştirmede, bir listenin aksine bir diziyi ne zaman kullanmalıyım?

Bir sekansın ne zaman daha iyi olacağını görebilmemin bazı nedenleri:

  • Gerektiren diğer .NET dilleri veya kütüphaneler ile etkileşim zaman IEnumerable<T>.
  • Sonsuz bir diziyi temsil etmesi gerekir (muhtemelen pratikte gerçekten kullanışlı değildir).
  • Tembel değerlendirmeye ihtiyacınız var.

Başkaları var mı?


3
Sonsuz dizileri çok kullanışlı ve yaygın buluyorum. Örneğin, System.Random.Next () zaten "sonsuz dizi" olarak gizlenmiştir. Genellikle gerektiği kadar çok öğe üreten bir şey istiyorum. Geçenlerde F # dilinde bir Tetris yazdım ve blok oluşumunu sonsuz bir dizi olarak temsil ettim: oyun devam ettikçe gerektiği kadar üretecek.
Aşık

2
@Dr_Asik seqBu şekilde oluşturulmuş bir şeyin , ona her baktığınızda farklı rastgele sayılar üreteceğini unutmayın. Belli ki bu, deterministik olmayan hataların kaynağı olabilir ...
JD

Yanıtlar:


96

Bence ne zaman seçeceğinizle ilgili özetiniz Seqoldukça iyi. İşte bazı ek noktalar:

  • Seqİşlevleri yazarken varsayılan olarak kullanın , çünkü herhangi bir .NET koleksiyonuyla çalışırlar.
  • Veya Seqgibi gelişmiş işlevlere ihtiyacınız varsa kullanın.Seq.windowedSeq.pairwise

SeqVarsayılan olarak seçmenin en iyi seçenek olduğunu düşünüyorum , peki ne zaman farklı bir tür seçmeliyim?

  • Kalıpları Listkullanarak yinelemeli işlemeye ihtiyacınız olduğunda kullanın (standart kitaplıkta bulunmayan bazı işlevleri uygulamak için)head::tail

  • ListAdım adım oluşturabileceğiniz basit, değişmez bir veri yapısına ihtiyaç duyduğunuzda kullanın
    (örneğin, listeyi bir iş parçacığı üzerinde işlemeniz gerekiyorsa - bazı istatistikleri göstermek için - ve aynı anda listeyi aldığınız sırada başka bir iş parçacığında oluşturmaya devam edin. daha fazla değer, yani bir ağ hizmetinden)

  • ListKısa listelerle çalışırken kullanın - liste, değer genellikle boş bir listeyi temsil ediyorsa kullanılacak en iyi veri yapısıdır , çünkü bu senaryoda çok etkilidir

  • ArrayBüyük değer türleri koleksiyonlarına ihtiyaç duyduğunuzda kullanın
    (diziler verileri düz bir bellek bloğunda depolar, böylece bu durumda bellek açısından daha verimli olurlar)

  • ArrayRastgele erişime veya daha fazla performansa (ve önbellek konumuna) ihtiyacınız olduğunda kullanın


1
Çok teşekkürler - tam olarak peşindeydim. Size benzer işlevsellik sağlayan bu iki öğenin (liste ve sıra) neden olduğunu anlamak için F # öğrenirken kafa karıştırıcı.
dodgy_coder

3
"Kullanım Listbasit gerektiğinde [...] iletmenin veri yapısını [...] ve eş zamanlı adımı adım kurabileceğimizi listesini oluşturmaya devam başka iş parçacığı üzerinde [...]" Eğer üzerinde durmak misiniz senin burada anlamı / nasıl çalışıyor? Teşekkürler.
Narfanar

2
Fikir @Noein olduğunu size listeler üzerinde her zaman yinelerler can (bunlar iletmenin) ancak kullandığınız yeni listeler oluşturabilirsiniz x::xsüzerinde iterating sürecinde olabilecek mevcut işçileri bozmadanxs
Tomas Petriček

29

Ayrıca şu durumlarda tercih edin seq:

  • Tüm öğeleri aynı anda bellekte tutmak istemezsiniz.

  • Performans önemli değil.

  • Numaralandırmadan önce ve sonra bir şeyler yapmanız gerekir, örneğin bir veritabanına bağlanın ve bağlantıyı kapatın.

  • Birleştirme yapmıyorsunuz (tekrarlanan Seq.appendyığın taşacak).

Şu durumlarda tercih edin list:

  • Birkaç öğe var.

  • Çok fazla para harcayacak ve başını keseceksin.

Paralellik için seqne listiyidir ne de değildir , ancak bu onların da kötü olduğu anlamına gelmez. Örneğin, paralel olarak yapılacak küçük bir grup ayrı iş öğesini temsil etmek için ikisinden birini kullanabilirsiniz.


"Ne sekans ne de liste paralellik için iyidir": sekansın neden paralellik için iyi olmadığını açıklayabilir misiniz? O halde paralellik için ne iyidir, sadece dizi mi?
Aşık

5
@Dr_Asik Diziler en iyisidir çünkü onları tekrar tekrar alt bölümlere ayırabilir ve iyi bir referans konumunu koruyabilirsiniz. Ağaçlar bir sonraki en iyisidir çünkü onları da alt bölümlere ayırabilirsiniz, ancak referans konumu o kadar iyi değildir. Listeler ve diziler kötüdür çünkü onları alt bölümlere ayıramazsınız. Alternatif öğeler üretirseniz, olası en kötü referans bölgesini elde edersiniz. Guy Steele, yerelliği (diğer adıyla önbellek karmaşıklığı ) değil, yalnızca çalışma ve derinliği dikkate almasına rağmen paralelliği engelleyen doğrusal koleksiyonları tartıştı . labs.oracle.com/projects/plrg/Publications/…
JD

12

Küçük bir nokta: Seqve paralellikten Arraydaha iyidir List.

Birkaç seçeneğiniz var: PSeq F # PowerPack gelen Array.Parallel modülü ve Async.Parallel (asenkron hesaplama). Liste, sıralı yapısı ( head::tailkompozisyonu) nedeniyle paralel yürütme için kötüdür .


Bu iyi bir nokta - aklımdaki senaryo, koleksiyonu bir iş parçacığı üzerine (yani bazı hizmetlerden değerler alırken) ve onu başka bir iş parçacığından (yani istatistikleri hesaplamak ve görüntülemek için) oluşturmanız gerektiğiydi. Paralel işlem için (hafızadaki tüm verilere sahip olduğunuzda), sahip olmak Arrayveya PSeqçok daha iyi olduğunu kabul ediyorum .
Tomas Petricek

1
Neden bunun paralellikten seqdaha iyi olduğunu söylüyorsunuz list? seqsıralı yapıları nedeniyle paralel yürütme için de korkunçlar ...
JD

7

liste daha işlevsel, matematik dostudur. her eleman eşit olduğunda, 2 liste eşittir.

sıra değil.

let list1 =  [1..3]
let list2 =  [1..3]
printfn "equal lists? %b" (list1=list2)

let seq1 = seq {1..3}
let seq2 = seq {1..3}
printfn "equal seqs? %b" (seq1=seq2)

görüntü açıklamasını buraya girin


5

Her zaman Seqgenel API'lerinizde ifşa etmelisiniz . Dahili uygulamalarınızda Listve kullanın Array.


Bunun nedeni diğer .NET dilleriyle iyi çalıştıkları için mi? yani a bir Seqolarak görüldüğü için IEnumerable<T>?
dodgy_coder

İyi tasarım uygulamaları nedeniyle hayır. Gerektiği kadar bilgiyi açığa çıkarın, daha fazla değil.
Aleš Roubíček

Tamam adil yorum, bu C # kodu için de iyi bir uygulamadır - yani bir işlev, örneğin daha ağır List <T> yerine IEnumerable <T> olarak tanımlanabilir.
dodgy_coder

1
Değişken dönüş yapılarının (örneğin .NET'teki bu tasarım hatası: msdn.microsoft.com/en-us/library/afadtey7.aspx ) veya diğer .NET dillerinden kullanılabilen API'lerin bağlamlarını kabul ediyorum ancak kabul etmiyorum Kısmen seqparalellik için çok kötü oldukları için genel olarak katılıyorum .
JD
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.