2011-12-20 3 views
32

Scala: What is the difference between Traversable and Iterable traits in Scala collections?How would I get the sum of squares of two Lists in Scala?などの質問が部分的に答えています。私はこのすべてを1つの場所でカバーする質問が理にかなっていると感じました。Scalaのセマンティクスは、トラバース、反復可能、シーケンス、ストリーム、およびビューですか?

+3

私はScalaが進化するにつれて情報が失効する可能性があるため、これは実際には特定の質問ではありませんが、一般的にはそうではないため、1)一般的なケースは既にこのような幅広い調査(Scala、他の多くの言語とは異なります)のためのよりよいリソースである、[Scalaの独自のドキュメント](http://www.scala-lang.org/docu/files/collections-api/collections.html)非常に困難な場合があります)。 – ig0774

+2

@ ig0774 2)私の意見では、観測可能な将来に大きく変化するのは、スカラコレクションのコア概念です。 –

+7

@ ig0774あなたの3つのポイントとは対照的に、1)私はこの質問が一般的に価値があり、簡潔に回答できるほど具体的であると感じているため2)現在のScalaコレクションの理解の中心にある3)現在の文書は広範囲ではあるが非常に広がっている。大きな画像を得るのは難しいです。 –

答えて

33

トラバーシブルは、コレクション階層の先頭です。その主な方法は 'foreach'なので、コレクションの各要素に対して何かをすることができます。

Iterableは、foreachを実装できるIteratorを作成できます。これは要素のいくつかの順序を定義しますが、その順序はすべての反復子で変更される可能性があります。

Seq(要素)は、要素の順序が固定されているイテラブルです。したがって、要素のインデックスについて話すことは理にかなっています。

ストリームはレイジーシーケンスです。私。ストリームの要素がアクセスされる前に計算されないことがあります。これにより、すべての整数のシーケンスのような無限のシーケンスで作業することが可能になります。

ビューは、コレクションの非厳格なバージョンです。フィルタやマップのようなメソッドは、それぞれの要素がアクセスされたときに渡された関数を実行するだけです。したがって、巨大コレクションのマップは、元のコレクションの周りにラッパーを作成するだけですぐに戻ります。 1つの要素にアクセスする場合にのみ、その要素のマッピングが実際に実行されます。 Viewはクラスではありませんが、さまざまなコレクションのXxxViewクラスがたくさんあります。

+9

ビューは怠惰ではなく、厳密ではありません。怠惰にはキャッシュが必要ですが、ストリームは行いますが、ビューはそうしません。 –

+0

清潔さをありがとう。答えに固定しました。 –

+4

@ DanielC.Sobral "怠惰はキャッシュを必要とする" - うん、何? –

2

1つのコメントストリーム対反復子を追加したいと思います。ストリームとイテレータの両方を使用して、必要になるまで値を計算しない、厳密ではない、潜在的に無限のコレクションを実装することができます。

しかし、これを実行するときに発生する「早すぎる実行」には問題があります。イテレータは使用できますがストリームは使用できません。プロセスでは、この2つの重要な意味の違いが示されます。これはおそらく、最も明確に次のように示されている:

def runiter(start: Int) { 
    // Create a stream that returns successive integers on demand, e.g. 3, 4, 5, .... 
    val iter = { 
    def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1) 
    loop(start) 
    } 
    // Now, sometime later, we retrieve the values .... 
    println("about to loop") 
    for (x <- iter) { 
    if (x < 10) println("saw value", x) else return 
    } 
} 

このコードは、指定された値で始まり、連続した整数を返し、無限ストリームを生成します。これは、インターネット接続を開き、必要に応じて接続から値を返すなど、より複雑なコードのスタンドインとして使用されます。

結果:

scala> runiter(3) 
(I computed a value,3) 
about to loop 
(saw value,3) 
(I computed a value,4) 
(saw value,4) 
(I computed a value,5) 
(saw value,5) 
(I computed a value,6) 
(saw value,6) 
(I computed a value,7) 
(saw value,7) 
(I computed a value,8) 
(saw value,8) 
(I computed a value,9) 
(saw value,9) 
(I computed a value,10) 

注意慎重に最初の値を計算するために必要な実行は、ストリームの値が実際に使用されている場所前に発生しますか。この初期実行でファイルやインターネット接続を開くなど、ストリームを作成した後で値が使用されるまでに時間がかかる場合、これは非常に問題になる可能性があります。開いているファイル記述子あなたのインターネット接続がタイムアウトになり、すべてが失敗する可能性があります。

単純では動作しません最初の空のストリームを使用して、それを修正しようとする:(前と同じ)

def runiter(start: Int) { 
    // Create a stream that returns successive integers on demand, e.g. 3, 4, 5, .... 
    val iter = { 
    def loop(v: Int): Stream[Int] = { println("I computed a value", v); v} #:: loop(v+1) 
    Stream[Int]() ++ loop(start) 
    } 
    // Now, sometime later, we retrieve the values .... 
    println("about to loop") 
    for (x <- iter) { 
    if (x < 10) println("saw value", x) else return 
    } 
} 

結果:しかし

scala> runiter(3) 
(I computed a value,3) 
about to loop 
(saw value,3) 
(I computed a value,4) 
(saw value,4) 
(I computed a value,5) 
(saw value,5) 
(I computed a value,6) 
(saw value,6) 
(I computed a value,7) 
(saw value,7) 
(I computed a value,8) 
(saw value,8) 
(I computed a value,9) 
(saw value,9) 
(I computed a value,10) 

、あなたはによってこの問題を解決することができます初期の空のイテレータを使用してイテレータにストリームを変更します。

def runiter(start: Int) { 
    // Create an iterator that returns successive integers on demand, e.g. 3, 4, 5, .... 
    val iter = { 
    def loop(v: Int): Iterator[Int] = { println("I computed a value", v); Iterator(v)} ++ loop(v+1) 
    Iterator[Int]() ++ loop(start) 
    } 
    // Now, sometime later, we retrieve the values .... 
    println("about to loop") 
    for (x <- iter) { 
    if (x < 10) println("saw value", x) else return 
    } 
} 

結果:あなたが最初の空の反復子を追加しない場合、あなたはストリームと同じ時期尚早実行問題に実行されることを

scala> runiter(3) 
about to loop 
(I computed a value,3) 
(saw value,3) 
(I computed a value,4) 
(saw value,4) 
(I computed a value,5) 
(saw value,5) 
(I computed a value,6) 
(saw value,6) 
(I computed a value,7) 
(saw value,7) 
(I computed a value,8) 
(saw value,8) 
(I computed a value,9) 
(saw value,9) 
(I computed a value,10) 

注意。

+3

ストリーム版では、 "val iter"を "def iter"に変更できます。これはトリックを行います。 –

関連する問題