リストではなくF#でシーケンスを使用するのはいつですか?


82

リストには実際には値が含まれており、シーケンスはのエイリアスであることを理解していますIEnumerable<T>。実際のF#開発では、リストではなくシーケンスをいつ使用する必要がありますか?

シーケンスがいつより良くなるかを私が見ることができるいくつかの理由はここにあります:

  • を必要とする他の.NET言語またはライブラリと対話する場合 IEnumerable<T>
  • 無限のシーケンスを表す必要があります(おそらく実際にはあまり役に立ちません)。
  • 遅延評価が必要です。

他にありますか?


3
無限のシーケンスは非常に便利で一般的だと思います。たとえば、System.Random.Next()は、すでに変装した「無限シーケンス」です。多くの場合、必要な数の要素を生成するものが必要です。私は最近、F#でテトリスを作成し、ブロック生成を無限のシーケンスとして表現しました。ゲームが進むにつれて、必要な数だけ作成されます。
Asik 2012年

2
@Dr_Asikseqそのように生成されたものは、見るたびに異なる乱数を生成することに注意してください。これは明らかに非決定的なバグ...の源となり得る
JD

回答:


96

いつ選ぶべきかについてのあなたの要約Seqはかなり良いと思います。ここにいくつかの追加のポイントがあります:

  • Seq関数を作成するときにデフォルトで使用します。これは、関数が任意の.NETコレクションで機能するためです。
  • またはのSeqような高度な機能が必要な場合に使用しますSeq.windowedSeq.pairwise

Seqデフォルトで選択するのが最善のオプションだと思いますが、いつ別のタイプを選択しますか?

  • 使用Listあなたが使用して再帰的な処理を必要とするhead::tailパターンを
    (標準ライブラリでは利用できないいくつかの機能を実装するために)

  • Listステップバイステップで構築できる単純な不変のデータ構造が必要な場合に使用します
    (たとえば、あるスレッドでリストを処理する必要がある場合(統計を表示するため)、同時に別のスレッドでリストを作成し続ける必要がある場合)より多くの値、つまりネットワークサービスから)

  • List短いリストで作業するときに使用します-リストは、値が空のリストを表すことが多い場合に使用するのに最適なデータ構造です。そのシナリオでは非常に効率的だからです

  • Array値型の大規模なコレクションが必要な場合に使用します
    (配列はフラットメモリブロックにデータを格納するため、この場合はメモリ効率が高くなります)

  • Arrayランダムアクセスまたはより高いパフォーマンス(およびキャッシュの局所性)が必要な場合に使用します


1
どうもありがとう-まさに私が求めていたもの。F#を学習して、同様の機能を提供するこれら2つの要素(listとseq)がある理由を理解するときは混乱します。
dodgy_coder 2012年

3
「ステップバイステップで構築できるList単純な不変のデータ構造が必要な場合は[...]を使用し、同時に別のスレッドでリストの構築を続行します[...]」詳細を教えてください。ここでの意味/それはどのように機能しますか?ありがとう。
Narfanar 2015

2
@Noeinアイデアは、リストをいつでも繰り返すことができる(リストは不変である)がx::xs、繰り返しの過程にある可能性のある既存のワーカーを壊すことなく、を使用して新しいリストを作成できるということですxs
Tomas Petricek 2015

29

次のseq場合も優先します。

  • すべての要素を同時にメモリに保持する必要はありません。

  • パフォーマンスは重要ではありません。

  • 列挙の前後に何かを行う必要があります。たとえば、データベースに接続して接続を閉じます。

  • 連結していません(繰り返されるSeq.appendとスタックオーバーフローが発生します)。

次のlist場合に優先します。

  • いくつかの要素があります。

  • あなたはたくさんの前置きと斬首をするでしょう。

どちらseqlist並列処理には適していませんが、必ずしもそれらが悪いことを意味するわけではありません。たとえば、どちらかを使用して、並行して実行される個別の作業項目の小さな束を表すことができます。


「seqもlistも並列処理に適していない」:seqが並列処理に適していない理由を詳しく説明していただけますか?では、並列処理には何が良いのでしょうか、配列のみですか?
Asik 2012年

5
@Dr_Asik配列は、再帰的に細分化し、参照の局所性を維持できるため、最適です。木は細分化することもできるので次善の策ですが、参照の局所性はそれほど良くありません。リストとシーケンスは細分化できないため、問題があります。代替要素をファームアウトすると、参照の局所性が最悪になります。Guy Steeleは、作業と深さのみを考慮し、局所性(別名キャッシュの複雑さ)は考慮していませんが、並列処理を妨げる線形コレクションについて説明しました。labs.oracle.com/projects/plrg/Publications/…–
JD

12

ほんの1つの小さなポイント:Seqそして並列処理Arrayよりも優れListています。

F#PowerPackのPSeqArray.Parallelモジュール、Async.Parallel(非同期計算)のいくつかのオプションがあります。リストは、そのシーケンシャルな性質(head::tail構成)のため、並列実行にはひどいです。


それは良い点です-私が考えていたシナリオは、あるスレッドでコレクションを構築し(つまり、あるサービスから値を受け取るときに)、別のスレッドからそれを使用する(つまり、統計を計算して表示する)必要がある場合でした。並列処理(すでにすべてのデータがメモリにある場合)の場合、持っているArrayPSeq、はるかに優れていることに同意します。
Tomas Petricek 2012年

1
なぜそれseqlist並列処理よりも優れていると言うのですか?seqシーケンシャルな性質のため、並列実行にもひどいです...
JD 2012年

7

リストはより機能的で、数学に適しています。各要素が等しい場合、2つのリストは等しくなります。

シーケンスはそうではありません。

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)

ここに画像の説明を入力してください


5

常にSeqパブリックAPIで公開する必要があります。ListArrayを内部実装で使用します。


それは、他の.NET言語でうまく機能するからですか?つまり、aSeqIEnumerable<T>
dodgy_coder 2012年

いいえ、それは優れた設計慣行のためです。必要なだけの情報を公開します。
エールRoubíček

公正なコメントですが、これはC#コードにも適しています。つまり、関数は、たとえば、重いList <T>ではなくIEnumerable <T>として定義するのが最適な場合があります。
dodgy_coder 2012年

1
可変の戻り構造(たとえば、.NETのこの設計上の欠陥:msdn.microsoft.com/en-us/library/afadtey7.aspx)または他の.NET言語から使用される可能性のあるAPIのコンテキストに同意しますが、同意しません。seq並列処理に非常に悪いという理由もあり、一般的に同意します。
JD
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.