質問

の書籍"のプログラミングスカラ",第23の例のように:

case class Book(title: String, authors: String*)
val books: List[Book] = // list of books, omitted here
// find all authors who have published at least two books

for (b1 <- books; b2 <- books if b1 != b2;
    a1 <- b1.authors; a2 <- b2.authors if a1 == a2)
yield a1

著者は、この翻訳:

books flatMap (b1 =>
   books filter (b2 => b1 != b2) flatMap (b2 =>
      b1.authors flatMap (a1 =>
        b2.authors filter (a2 => a1 == a2) map (a2 =>
           a1))))

だけに地図やflatmap方法の定義TraversableLike.scala)よく目にすることでしょう、と定義されたループ:

   def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
    val b = bf(repr)
    b.sizeHint(this) 
    for (x <- this) b += f(x)
    b.result
  }

  def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
    val b = bf(repr)
    for (x <- this) b ++= f(x)
    b.result
  }

もないといけないと思い、このために継続的に次のように変換されforeachして翻訳されながらの声を構築な表現scalaないために構築でいるものの利回り。

なので、だいたい話だが、なぜScalaこの"翻訳"?筆者の使用例4-発電機は、翻訳の4レベルの入れ子ループは思って本当に恐ろしい性能が books が大きい。

スカーラを使用するよう努めているこのような"統語砂糖"では、常に参照することがわかっ重用フィルタの図flatmap、そのようにプログラマを忘れようんでネストワンループ内の他、何を達成しているので、コードパッケージをダウンロードするも短縮できます。自分の考えたんですか?

役に立ちましたか?

解決

内包表記の場合は、モナド変換のためのシンタックスシュガーであり、、など、場所のあらゆる種類のに有用です。その時、彼らははるかに詳細なスカラ座での同等のHaskellの構造よりも(もちろん、Haskellは1は、Scalaの中のような構造のパフォーマンスについて話すことはできませんので、デフォルトでは非厳密である)。

また、重要な、この構築物は明確に行われているものを維持し、かつ迅速にエスカレートインデントや不要なプライベートメソッドのネストを回避します。

はとしては、最終的な考察に、その皮革複雑かどうか、私はこれを断定ます

for {
  b1 <- books
  b2 <- books
  if b1 != b2
  a1 <- b1.authors
  a2 <- b2.authors 
  if a1 == a2
} yield a1

これが行われているかを確認することは非常に簡単で、複雑さは明確である:B ^ 2 * ^ 2(フィルターは複雑さを変更しません)、書籍や著者の数の数について。さて、深いインデントまたは民間の方法のいずれかで、Javaで同じコードを書き、コードの複雑さが何であるかを、簡単に見に、確認するためにしようとします。

だから、私見、これは複雑さを隠し、しかし、逆に、それは明らかにしません。

についてはmap / flatMap彼らは適用されませんので、/ filter定義あなたが言及し、彼らは、Listまたは他のクラスにも属しません。基本的には、

for(x <- List(1, 2, 3)) yield x * 2
に変換されます。

List(1, 2, 3) map (x => x * 2)

それは

と同じものではありません
map(List(1, 2, 3), ((x: Int) => x * 2)))
あなたが渡された定義が呼び出されることになる方法です。

。記録のために、mapListの実際の実装は、次のとおりです。

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
  val b = bf(repr)
  b.sizeHint(this) 
  for (x <- this) b += f(x)
  b.result
}

他のヒント

それは理解し、維持するために簡単ですように、

私は、コードを記述します。私は、プロファイル。私は私の注意を捧げるところだボトルネックがある場合。それは何かにだ場合は説明してきたように私は別の方法で問題を攻撃します。それまでは、私は「砂糖」を愛しますそれは私に物事を書いたり、それについてハード思考の手間が省けます。

6つのループが実際にあります。各フィルタ/ flatMap /マップの一のループ

フィルター - >マップペアが

(イテレータメソッド)コレクションの怠惰なビューを使用することによって一つのループで行うことができ

一般的に、TTは、1冊本の著者は、他の著者のリストにある場合に見つけるために、すべての本のペアと、2つのネストされたループを見つけるために、書籍の2つのネストされたループを実行している。

明示的にコーディングする際に、単純なデータ構造を使用して、あなたが同じことをするだろう。

そしてもちろん、ここでの例では、「for」ループ複合体を示すために、最も効率的なコードを書くことではありません。例えば、代わりに、著者の一連の、1がセットを使用して、交差点が非空であれば見つけることができます:

for (b1 <- books; b2 <- books; a <- (b1.authors & b2.authors)) yield a

一ォ@IttayDの答えは、アルゴリズムの効率。ではここで注目されるアルゴリズムのオリジナルポスト(書籍) 入れ子ループjoin.実際には、こんなアルゴリズムのための大規模なデータセットは、データベースの使用 ハッシュ計 こちらです。にスカラ、ハッシュ集合うようなもの:

(for (book <- books;
      author <- book.authors) yield (book, author)
).groupBy(_._2).filter(_._2.size > 1).keys
scroll top