実施スカーラコレクションマップ、フィルター等の権不要タイプ
-
26-09-2019 - |
質問
ようにしていを実施する デフォルト値地図, ていただきたいと思いますようにフィル、地図など。以上 DefaultingMap
ものを DefaultingMap
となりました。ここでの私の初期の実装:
class DefaultingMap[K, V](defaultValue: => V)
extends mutable.HashMap[K, V]
with mutable.MapLike[K, V, DefaultingMap[K, V]] {
override def empty = new DefaultingMap[K, V](defaultValue)
override def default(key: K): V = {
val result = this.defaultValue
this(key) = result
result
}
}
私物の種類 DefaultingMap
利用の場合 filter
, な利用の場合 map
:
scala> val counter = new DefaultingMap[Char, Int](0)
counter: DefaultingMap[Char,Int] = Map()
scala> for (c <- "ababcbbb") counter(c) += 1
scala> counter.filter{case (k, v) => v > 1}
res1: DefaultingMap[Char,Int] = Map((a,2), (b,5))
scala> counter.map{case (k, v) => (k, v * 2)}
res2: scala.collection.mutable.HashMap[Char,Int] = Map((a,4), (c,2), (b,10))
の違いをこの二つの方法がと map
間の暗黙的な CanBuildFrom
.んの収集を必要とすることをい implicit def
どこかの提供 CanBuildFrom
.私の初めての直感にしたいのでHashMap:
object DefaultingMap extends generic.MutableMapFactory[DefaultingMap] {
def empty[K, V]: DefaultingMap[K, V] = // Not possible!
implicit def canBuildFrom[K, V]:
generic.CanBuildFrom[Coll, (K, V), DefaultingMap[K, V]] =
new MapCanBuildFrom[K, V]
}
こうすることがコンパイルすが、このアプローチが成り立たないと思うので不可能を定義する empty
方法が必要になりうる defaultValue
きます。う場を定義する CanBuildFrom
クラス自体ではなく、仲間のオブジェクトではいつでも大丈夫なので defaultValue
はご用意ございます。※
どのように取得します。
解決
変更可能なマップはScalaではBuilder
sているので、デフォルトでMapFactory
はビルダーを取得するために、問題のタイプの空のマップを取ります。
は、あなたができることの一つはcollection.generic.MapFactory
に似たカスタムファクトリを定義することです。あなたはそこのような同様の方法でそれを定義する必要がありますが、empty
方法とnewBuilder
方法の両方がdefaultValue
ための追加の引数を取ることになるだろう。
の線に沿って何か(あなたが他のリンクでのScala 2.8コレクションAPIについての続きを読む場合は、あなたがマップのための一般的なコンパニオンオブジェクトを実装する必要がないことを見つける、提案):
import collection._
class DefaultingMap[K, V](val defaultValue: V)
extends mutable.HashMap[K, V]
with mutable.MapLike[K, V, DefaultingMap[K, V]] {
override def empty = new DefaultingMap(defaultValue)
}
object DefaultingMap {
def newBuilder[K, V](d: V): DefaultingMap[K, V] = new DefaultingMap[K, V](d)
implicit def canBuildFrom[K, V] =
new generic.CanBuildFrom[DefaultingMap[K, V], (K, V), DefaultingMap[K, V]] {
def apply(from: DefaultingMap[K, V]) = newBuilder[K, V](from.defaultValue)
def apply() = error("unsupported default apply")
}
}
object Main {
def main(args: Array[String]) {
println((new DefaultingMap[Int, Int](5)).defaultValue)
println(((new DefaultingMap[Int, Int](5)).map(x => x)).defaultValue)
}
}
プリントます:
$ scalac defaulting.scala
$ scala Main
5
5
私は認める、まだ、これはパラメータなしのapply
のための問題を解決していません。
他のヒント
ご利用の場合 collection.immutable.Map
2.8以上の withDefault
方法で利用可能:
val m = collection.immutable.Map(1->"a", 2->"b", 3->"c")
val n = m withDefaultValue "default"
// n(7) will return "default"
更新
だマッピングコレクションでの移動に withDefaultValue
前処理チェーン
val o = (for ((k, v) <- m) yield (k, v)) withDefaultValue "default"
// o(0) will return "default"
[OK]を、ここでは非常に、非常に近い私が欲しいものへのアプローチがあります:
class DefaultingMap[K, V](defaultValue: => V)
extends mutable.HashMap[K, V]
with mutable.MapLike[K, V, DefaultingMap[K, V]] {
override def empty = new DefaultingMap[K, V](defaultValue)
override def default(key: K): V = {
val result = this.defaultValue
this(key) = result
result
}
implicit def canBuildFrom[NK] =
new generic.CanBuildFrom[DefaultingMap[K, V], (NK, V), DefaultingMap[NK, V]] {
def apply(from: DefaultingMap[K, V]) =
new DefaultingMap[NK, V](from.newDefaultValue)
def apply() =
new DefaultingMap[NK, V](defaultValue)
}
def newDefaultValue = defaultValue
}
さて、私はスコープにそのCanBuildFrom
を取得する場合、すべてが魔法のように動作します:
scala> val counter = new DefaultingMap[Char, Int](0)
counter: DefaultingMap[Char,Int] = Map()
scala> for (c <- "ababcbbb") counter(c) += 1
scala> import counter._
import counter._
scala> counter.map{case (k, v) => (k, v * 2)}
res1: DefaultingMap[Char,Int] = Map((a,4), (c,2), (b,10))
scala> for ((k, v) <- counter; if v > 1) yield (k.toString, v * 2)
res2: DefaultingMap[java.lang.String,Int] = Map((a,4), (b,10))
私はそのimport counter._
オフのままならば、しかし、私は前と同じ動作を取得します。私はちょうど発見されることimplicit def canBuildFrom
を取得する方法を見つけ出すことができれば、私は...
これはmap
の戻り値の型であなたを助けにはなりません(しかし、その後、再び、新しいコレクションのデフォルト値は、一般的にmap
変換を使用して定義することはできません)。しかし、あなたは別のアプローチを得ます:
class DefaultHashMap[A, B](dflt: => B) extends scala.collection.mutable.Map[A, B] {
val underlying = new scala.collection.mutable.HashMap[A, B]()
def get(key: A) = underlying.get(key) orElse Some(default(key))
def iterator: Iterator[(A, B)] = underlying.iterator
def +=(kv: (A, B)) = { underlying += kv; this }
def -=(key: A) = { underlying -= key; this }
override def empty: DefaultHashMap[A, B] = new DefaultHashMap[A, B](dflt)
override def default(key: A) = dflt
}