2017-03-21 16 views
0

私は少し混乱しています。私はScalaにコードを持っています(正確なコードはそれほど重要ではありません)。 Seq [T]を取るために書いたすべての方法がありました。これらのメソッドは主にテール再帰的であり、Seq()のように最初に供給されるアキュムレータとしてSeq [T]を使用します。興味深いことに、すべてのシグネチャを具体的なList()実装と入れ替えると、パフォーマンスが3倍に向上しています。Scala Seqとリストのパフォーマンス

Seqのデフォルトの実装が実際不変なリストではないのですか?だからこそ、本当に何が起こっているのですか?

+1

これを実証するコードがありますか? – puhlen

+0

'Seq'のデフォルトの実装は実際に' ArrayBuffer'であり、 'List'ではありません。あなたが持っているユースケースは実際には 'List'sのために作られています。なぜなら、tail-recursivelyで実装されているからです。 –

+0

そのような巨大なパフォーマンスの違いが生じるのでしょうか? – Zahari

答えて

1

Seq(1,2,3)を呼び出し、List(1,2,3)を呼び出すと、いずれも1 :: 2 :: 3 :: Nilになります。 Seq.apply方法は次のようになりますだけで非常に一般的な方法である:

def apply[A](elems: A*): CC[A] = { 
    if (elems.isEmpty) empty[A] 
    else { 
    val b = newBuilder[A] 
    b ++= elems 
    b.result() 
    } 
} 

newBuilderここ事項のその種のものです。 scala.collection.immutable.Seq.newBuilderからThat method代表者:

def newBuilder[A]: Builder[A, Seq[A]] = new mutable.ListBuffer 

のでSeqためBuildermutable.ListBufferです。 Seqは、このように実装され、空のListBufferに要素を追加した後、その上にresultを呼び出すことによって構成されます:

def result: List[A] = toList 

/** Converts this buffer to a list. Takes constant time. The buffer is 
* copied lazily, the first time it is mutated. 
*/ 
override def toList: List[A] = { 
    exported = !isEmpty 
    start 
} 

ListBuilderとしてListBufferを有しています。それはわずかに異なるが同様の構築プロセスを経る。私はあなたのアルゴリズムの大部分がSeqに先行することから成り、全体としてSeq.apply(...)を呼び出さないことを前提としているので、それでは大きな違いは生じません。もしあなたがそれをしたとしても、大きな違いはありません。

あなたは、その動作をしているコードを見ずに見ている動作を引き起こしていると言うことは本当にできません。

+0

Seq.applyが単なるリストであり、大きな違いをもたらさなかったとの前提に従えば、実際にはそういうことができるでしょう: val sequence:LinearSeq [_] = Seq() これは、Seqがリストであり、ListがLinearSeq特性を使用するので、これはうまくいくはずです。しかし、これはうまくいかず、この理由から、特に効率的なテールアクセスやテール再帰的操作(つまり、シーケンスに対して反復を実行するメソッド)が必要な場合は、シーケンスを構築する方法が重要です。 –

+0

いいえ 'Seq()'は 'List'を返しますが、静的な' return type'は 'Seq'です。そのため、 'LinearSeq'型の変数に割り当てることができないのです。 'Seq(1).getClass'を評価し、何を得るかを見てください。 –

+0

しかし、明確にするためには、 'List'の性能特性を望むならば' List'を使う方が良いと私は同意します。 –

関連する問題