3

問題はここにあります: http://rosalind.info/problems/subs/

私が持っている質問は、以下に示す 2 つのソリューションのパフォーマンスに関係しています。

1.

  def indexOfAppearances(strand: String, subStrand: String): List[Int] = {
    def help0(x: String, y: String, accu: List[Int]): List[Int] =
      (x contains y) match {
        case true => {
          val index = (x indexOfSlice y) /* index where substring appears */
          val adjust = strand.length - x.length
          /* adjustment since the x has all the previous
               * nucleotides removed.
               */

          val newX = x.drop(index + 1).mkString
           /* here's the drop of index + 1 elements */
          help0(newX, y, (index + adjust) :: accu) /* tail recursive call */
        }
        case false => accu
      }

     help0(strand, subStrand, List()).reverse.toList.map(x => x + 1)
         //indexes are not from 0 but from 1
  }

2.

  val s = "ACGTACGTACGTACGT"
  val t = "GTA"

  val combs = s.sliding(t.length).zipWithIndex
  val locations = combs.collect { case (sub, i) if (sub == t) => i + 1 }
  println(locations.mkString(" "))

2 番目の解決策は、美しく機能的で短いものです。

最初のソリューションは少し大きいですが、それでも機能します。val を省略して、値を操作して短くすることもできましたが、それは私の目標ではありませんでした。

2番目の解決策を見た後、コードの長さのために私はかなりがっかりしました。scala ライブラリをチェックして、2 番目のソリューションが機能する理由を確認し、自分で再実装しました。両方のソリューションのパフォーマンスをチェックすることを考え、巨大な 3000 万の DNA ストランドを作成しました。

驚いた!

パフォーマンス:

最初の数字は DNA の長さで、次の 2 つの数字は 1 番目と 2 番目のソリューションの実行時間 (ms) を表します。

11,226,096 - 4921 - 14503

33,678,288 - 6448 - 35150

性能がこんなに違うのはなぜ?

scala ライブラリをチェックしてみましたが、この動作を説明するものは見つかりませんでした。

最初の解決策は多くのオブジェクトを作成するため、より多くのメモリを消費し、それを行うのに多くの時間がかかると思いましたが、何らかの理由ではるかに高速に動作するようです. 末尾の再帰ではないかと思いますし、zipWithIndex に時間がかかるとは思えません。イテレータは単なるイテレータですか?

ありがとう!

4

1 に答える 1

2

sliding文字列では効率的ではありません。文字列を文字に分解し、ボックス化してから、文字列に再構成します。

これを行うための最速の方法は、まだ信じられないほど難しいことではありませんが、のregionMatchesメソッドを使用することStringです。(DNAを使用すると、すべてがバイトに変換され、2ビットのニブルに変換されてint配列にパックされます。)

于 2012-11-08T22:17:09.307 に答える