受this question的啓發,我想在斯卡拉實現一個Multiset。我想一個MultiSet[A]
到:實現一個multiset /包作爲斯卡拉集合
- 支持添加,刪除,並集,交集和差
- 是
A => Int
,提供每個元素的計數
這裏有一個方法,延長Set
:
import scala.collection.immutable.Map
import scala.collection.immutable.Set
import scala.collection.SetLike
import scala.collection.mutable.Builder
class MultiSet[A](private val counts: Map[A, Int] = Map.empty[A, Int])
extends SetLike[A, MultiSet[A]] with Set[A] {
override def +(elem: A): MultiSet[A] = {
val count = this.counts.getOrElse(elem, 0) + 1
new MultiSet(this.counts + (elem -> count))
}
override def -(elem: A): MultiSet[A] = this.counts.get(elem) match {
case None => this
case Some(1) => new MultiSet(this.counts - elem)
case Some(n) => new MultiSet(this.counts + (elem -> (n - 1)))
}
override def contains(elem: A): Boolean = this.counts.contains(elem)
override def empty: MultiSet[A] = new MultiSet[A]
override def iterator: Iterator[A] = {
for ((elem, count) <- this.counts.iterator; _ <- 1 to count) yield elem
}
override def newBuilder: Builder[A,MultiSet[A]] = new Builder[A, MultiSet[A]] {
var multiSet = empty
def +=(elem: A): this.type = {this.multiSet += elem; this}
def clear(): Unit = this.multiSet = empty
def result(): MultiSet[A] = this.multiSet
}
override def seq: MultiSet[A] = this
}
object MultiSet {
def empty[A]: MultiSet[A] = new MultiSet[A]
def apply[A](elem: A, elems: A*): MultiSet[A] = MultiSet.empty + elem ++ elems
def apply[A](elems: Seq[A]): MultiSet[A] = MultiSet.empty ++ elems
def apply[A](elem: (A, Int), elems: (A, Int)*) = new MultiSet((elem +: elems).toMap)
def apply[A](elems: Map[A, Int]): MultiSet[A] = new MultiSet(elems)
}
延伸Set
是好的,因爲這意味着MultiSet
自動克工會,差異等所有ETS定義下面將舉行:
// add
assert(
MultiSet("X" -> 3, "Y" -> 1) + "X" ===
MultiSet("X" -> 4, "Y" -> 1))
assert(
MultiSet("X" -> 3, "Y" -> 1) + "Z" ===
MultiSet("X" -> 3, "Y" -> 1, "Z" -> 1))
// remove
assert(
MultiSet("a" -> 2, "b" -> 5) - "b" ===
MultiSet("a" -> 2, "b" -> 4))
assert(
MultiSet("a" -> 2, "b" -> 5) - "c" ===
MultiSet("a" -> 2, "b" -> 5))
// add all
assert(
MultiSet(10 -> 1, 100 -> 3) ++ MultiSet(10 -> 1, 1 -> 7) ===
MultiSet(100 -> 3, 10 -> 2, 1 -> 7))
// remove all
assert(
MultiSet("a" -> 2, "b" -> 5) -- MultiSet("a" -> 3) ===
MultiSet("b" -> 5))
然而,我不得不重寫像union
和intersect
一些繼承的方法,因爲他們會做多集,例如錯誤的東西以下將不舉行:
// union (takes max of values)
assert(
MultiSet(10 -> 5, 1 -> 1).union(MultiSet(10 -> 3, 1 -> 7)) ===
MultiSet(10 -> 5, 1 -> 7))
// intersection (takes min of values)
assert(
MultiSet(10 -> 5, 100 -> 3).intersect(MultiSet(10 -> 1, 1 -> 7)) ===
MultiSet(10 -> 1))
延伸Set
另一個問題是,那麼我不能有MultiSet
是A => Int
,因爲我得到的錯誤:illegal inheritance; class MultiSet inherits different type instances of trait Function1: A => Int and A => Boolean
。我可以通過聲明一個單獨的方法來解決這個問題,比如count
方法,但我更喜歡這個類只是一個A => Int
。
另一種方法是從Map[A, Int]
繼承,這會給我我想要的A => Int
,但我必須定義自Map
這些將在(A, Int)
對來定義所有的我自己++
,--
等。 ,但對於multiset,他們需要通過A
來定義。
我想第三種方法是放棄Set
和Map
,只是實現一個新的子類Iterable
或其他什麼。
你會推薦什麼?在Scala集合框架中適合MulitSet
的最佳方法是什麼?
棘手的問題。我猜的是,如果你的'MultiSet'是'A => Int'或者'A => Boolean'。像集合中的操作一樣進行'過濾'是很常見的,因此將它看作是一種'存在'方法。如果你的集合應該是'A => Int',你可能需要創建一個模仿SetLike'的MultiSetLike特性。這樣你可以逃避'A =>布爾'定義。 – EECOLOR 2013-02-25 12:05:08