5

Scala のコレクションの設計から、次のようなことがわかります。

scala> BitSet(1,2,3) map (_ + "a")
res7: scala.collection.immutable.Set[String] = Set(1a, 2a, 3a)

中間データ構造を構築しません。新しい Set は、BitSet が Builder を使用して繰り返されるときに構築されます。実際、その場合、文字列のビットセットは意味をなさないため、明らかです。

リストからのマップはどうですか? 以下が中間リストを作成することは間違いありません。

scala> List(1,2,3) map (_ -> "foo") toMap
res8: scala.collection.immutable.Map[Int,java.lang.String] =
    Map(1 -> foo, 2 -> foo, 3 -> foo)

つまりリストList((1,foo), (2,foo), (3,foo))です。そうでない場合、どのように?では、以下はどうでしょうか。

scala> Map.empty ++ (List(1,2,3) map (_ -> "foo"))
res10: scala.collection.immutable.Map[Int,java.lang.String] =
    Map(1 -> foo, 2 -> foo, 3 -> foo)

今回は、のタイプから理解しているように見えるものから++

def ++ [B >: (A, B), That]
       (that: TraversableOnce[B])
       (implicit bf: CanBuildFrom[Map[A, B], B, That]): That

マップがその場で構築され、中間リストが構築されない場合があると思います。

そうですか?はいの場合、これは森林破壊を確実にする標準的な方法ですか、それとももっと簡単な構文がありますか?

4

2 に答える 2

14

を使用breakOutして、中間コレクションが作成されないようにすることができます。例えば:

// creates intermediate list.
scala> List((3, 4), (9, 11)).map(_.swap).toMap 
res542: scala.collection.immutable.Map[Int,Int] = Map(4 -> 3, 11 -> 9)

scala> import collection.breakOut
import collection.breakOut

// doesn't create an intermediate list.
scala> List((3, 4), (9, 11)).map(_.swap)(breakOut) : Map[Int, Int]
res543: Map[Int,Int] = Map(4 -> 3, 11 -> 9)

あなたはここでそれについてもっと読むことができます。

アップデート:

の定義を読むと、breakOut基本的にCanBuildFromは期待される型のオブジェクトを作成し、それをメソッドに明示的に渡す方法であることがわかります。breakOut次の定型文を入力する手間を省くだけです。

// Observe the error message. This will tell you the type of argument expected.
scala> List((3, 4), (9, 11)).map(_.swap)('dummy)
<console>:16: error: type mismatch;
 found   : Symbol
 required: scala.collection.generic.CanBuildFrom[List[(Int, Int)],(Int, Int),?]
              List((3, 4), (9, 11)).map(_.swap)('dummy)
                                                ^

// Let's try passing the implicit with required type.
// (implicitly[T] simply picks up an implicit object of type T from scope.)
scala> List((3, 4), (9, 11)).map(_.swap)(implicitly[CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]]])
// Oops! It seems the implicit with required type doesn't exist.
<console>:16: error: Cannot construct a collection of type Map[Int,Int] with elements of type (Int, Int) based on a coll
ection of type List[(Int, Int)].
              List((3, 4), (9, 11)).map(_.swap)(implicitly[CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]]])

// Let's create an object of the required type ...
scala> object Bob extends CanBuildFrom[List[(Int, Int)], (Int, Int), Map[Int, Int]] {
     |   def apply(from: List[(Int, Int)]) = foo.apply
     |   def apply() = foo.apply
     |   private def foo = implicitly[CanBuildFrom[Nothing, (Int, Int), Map[Int, Int]]]
     | }
defined module Bob

// ... and pass it explicitly.
scala> List((3, 4), (9, 11)).map(_.swap)(Bob)
res12: Map[Int,Int] = Map(4 -> 3, 11 -> 9)

// Or let's just have breakOut do all the hard work for us.
scala> List((3, 4), (9, 11)).map(_.swap)(breakOut) : Map[Int, Int]
res13: Map[Int,Int] = Map(4 -> 3, 11 -> 9)
于 2011-11-21T04:53:02.453 に答える
3

例1)正解です。中間リストはありません

2)はい、中間リストを取得します。

3)はい、括弧内にあるものから間欠的なリストを取得します。「魔法」は起こっていません。かっこで囲まれたものがある場合は、最初に評価されます。

ここで「森林破壊」とはどういう意味かわかりません。ウィキペディアによると、それは木の構造を排除することを意味します。中間リストを削除する場合は、ビューを使用する必要があります。たとえば、ここを参照してください:scalaの数値リストの変換を合計する

したがって、中間結果がなければ、あなたの例は次のようになります

BitSet(1,2,3).view.map(_ + "a").toSet

toSetそれ以外の場合はが必要なので必要ですIterableView[String,Iterable[_]]

List(1,2,3).view.map(_ -> "foo").toMap

Map.empty ++ (List(1,2,3).view.map(_ -> "foo"))

変換操作を実行する方法もありますがforce、これには、より一般的なタイプを返すという厄介な習慣があるようです(おそらく誰かが理由をコメントすることができます):

scala> Set(1,2,3).view.map(_ + 1).force
res23: Iterable[Int] = Set(2, 3, 4)
于 2011-11-21T04:13:40.627 に答える