集合中不包含a⊆b和b在集合中的位置

时间:2012-03-10 02:20:25

标签: scala scala-collections

我需要一个忽略其他元素的集合:

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(){_ == _}

1 个答案:

答案 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普通的旧集合语义(即,只有相等的事物相互排序,并且它们总是相等的)。