我需要一个忽略其他元素的集合:
Picky(Set(1, 2)) + Set(1) should equal(Picky(Set(1, 2)))
Picky(Set(1)) + Set(1, 2) should equal(Picky(Set(1, 2)))
Picky(Set(1, 3)) + Set(1, 2) should equal(Picky(Set(1, 3), Set(1, 2)))
Picky(Set(1, 2), (Set(1))) should equal(Picky(Set(1, 2)))
我实际上有一个解决方案
case class Picky[T] private(sets: Set[Set[T]]) {
def +(s: Set[T]): Picky[T] = Picky(Picky.internalAddition(this.sets, s))
}
object Picky {
def apply[T](sets: Set[T]*): Picky[T] =
Picky((Set[Set[T]]() /: sets)(internalAddition(_, _)))
private def internalAddition[T](c: Set[Set[T]], s: Set[T]): Set[Set[T]] =
if (c.exists(s subsetOf _)) c else c.filterNot(_ subsetOf s) + s
}
但是我想知道是否已经有一个包含这个概念的集合,因为我试图做的事情听起来有点像具有某种缩减功能的集合,类似于以下想象集合接受worse
函数(在我们的特定情况下为(a, b) => a subset b
):
PickySet(){(a, b) => a subset b}
如果worse(a, b)
返回true
{@ 1}},那么对于元素(a,b)的任何内容,a
将被丢弃
为了澄清与Set的区别,Set将是PickySet的一个特例:
PickySet(){_ == _}
答案 0 :(得分:1)
我认为你不会找到一个方便的现成的这个集合的实现,但你可以通过使用scala.math.PartialOrdering
以及集合部分排序的事实使你的更加通用。子集关系。
首先是Picky
的定义。实际上你想要的是一个只容纳maximal elements的容器,其中没有相互排序的元素,并且所有较小的元素都被删除了。
class Picky[A: PartialOrdering] private(val xs: Seq[A]) {
def +(y: A): Picky[A] = new Picky(Picky.add(xs, y))
override def toString = "Picky(%s)".format(xs.mkString(", "))
}
object Picky {
def apply[A: PartialOrdering](xs: A*): Picky[A] =
new Picky(xs.foldLeft(Seq.empty[A])(add))
private def add[A](xs: Seq[A], y: A)(implicit ord: PartialOrdering[A]) = {
val notSmaller = xs.filterNot(ord.lteq(_, y))
if (notSmaller.exists(ord.lteq(y, _))) notSmaller else notSmaller :+ y
}
}
接下来是集合的部分排序,仅在其中一个集合是另一个集合的子集时(可能是平凡的)定义:
implicit def subsetOrdering[A] = new PartialOrdering[Set[A]] {
def tryCompare(x: Set[A], y: Set[A]) =
if (x == y) Some(0)
else if (x subsetOf y) Some(-1)
else if (y subsetOf x) Some(1)
else None
def lteq(x: Set[A], y: Set[A]) =
this.tryCompare(x, y).map(_ <= 0).getOrElse(false)
}
以下tryCompare
的等效定义可能会更快一些:
def tryCompare(x: Set[A], y: Set[A]) = {
val s = (x & y).size
if (s == x.size || s == y.size) Some(x.size - y.size) else None
}
现在我们得到了预期的结果:
scala> Picky(Set(1, 2)) + Set(1)
res0: Picky[scala.collection.immutable.Set[Int]] = Picky(Set(1, 2))
scala> Picky(Set(1)) + Set(1, 2)
res1: Picky[scala.collection.immutable.Set[Int]] = Picky(Set(1, 2))
scala> Picky(Set(1, 3)) + Set(1, 2)
res2: Picky[scala.collection.immutable.Set[Int]] = Picky(Set(1, 3), Set(1, 2))
scala> Picky(Set(1, 2), (Set(1)))
res3: Picky[scala.collection.immutable.Set[Int]] = Picky(Set(1, 2))
请注意,我们可以非常轻松地定义一个替代的部分排序,它将赋予Picky
普通的旧集合语义(即,只有相等的事物相互排序,并且它们总是相等的)。