加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 如何使用用户定义的相等性实现集合

发布时间:2020-12-16 09:15:16 所属栏目:安全 来源:网络整理
导读:这个问题与 this one有关:是否可以在Scala中创建一个Set-like类(意味着它扩展了Set trait),用于定义包含关系的相等性是由用户定义而不是==? 测试这个真正有效的一种方法是检查过滤器是否返回相同的集合类型. // typeclass for equalitytrait Equals[T] { d
这个问题与 this one有关:是否可以在Scala中创建一个Set-like类(意味着它扩展了Set trait),用于定义包含关系的相等性是由用户定义而不是==?

测试这个真正有效的一种方法是检查过滤器是否返回相同的集合类型.

// typeclass for equality
trait Equals[T] {
  def isEqual(t1: T,t2: T): Boolean
}

// an object representing plane coordinates
case class Coordinate(i: Int,j: Int)

// an equality saying that 2 coordinates are equal if they are on 
// the same horizontal line
implicit def horizontalEquality: Equals[Coordinate] = new Equals[Coordinate] {
   def isEqual(t1: Coordinate,t2: Coordinate) = t1.i == t2.i
}

// we create an EqualitySet[T] where T must verify [T : Equals]     
val set = EqualitySet[Coordinate]()

// set2 must be of type EqualitySet[Coordinate]
val set2 = set.filter(_.i > 0)

解决方法

我们创建了这个解决方案,作为一个与Miles Sabin(@milessabin)进行Scala培训的团队.

import scala.collection.mutable.ListBuffer
import scala.collection.generic.CanBuildFrom
import scala.collection.SetLike
import scala.collection.mutable.Builder

/**
 * we extend Set[T] to provide the Set-like interface
 * we extends SetLike[T,EqualitySet[T]] to specify that Set methods will return
 *   instances of type EqualitySet (and not simply Set)
 */
trait EqualitySet[T] extends Set[T] with SetLike[T,EqualitySet[T]] { outer =>
  /** we need to provide an Equals[T] instance to create an EqualitySet[T] */
  implicit def equality: Equals[T]  

  /** our internal implementation as a list of elements */
  protected val set = ListBuffer[T]()

  /** we need to implements those 4 methods */
  def contains(t: T) = set.exists(equality.isEqual(_,t))
  def +(t: T) = { if (!contains(t)) set += t; this }
  def -(t: T) = { set -= t; this }
  def iterator = set.iterator

  /** we must be able to provide an empty set with the proper equality definition */
  override def empty = new EqualitySet[T] { 
    override def equality = outer.equality
  }
}  

/** 
 * Companion object for the EqualitySet class
 */
object EqualitySet {

  /** 
   * this implicit is absolutely necessary to be able to preserve the resulting
   * collection type when calling `filter`
   */
  implicit def canBuildFrom[T] = new CanBuildFrom[EqualitySet[T],T,EqualitySet[T]] {
    def apply(from: EqualitySet[T]): Builder[T,EqualitySet[T]] = 
      new Builder[T,EqualitySet[T]] {
        // use a ListBuffer internally to accumulate elements
        private val elems = ListBuffer[T]()
        def +=(t: T) = { 
          if (!elems.exists(from.equality.isEqual(_,t))) elems += t
          this
        } 
        def clear() = elems.clear

        // when we finish building the collection
        // we can return an EqualitySet with the original equality relation
        def result() = new EqualitySet[T] {
          override val set = elems
          override def equality = from.equality
        }
     }
     def apply(): Builder[T,EqualitySet[T]] = 
       sys.error("this can't be implemented,because no equality instance is provided")
  }

  /** @return an EqualitySet for a type T having an Equals instance */
  def apply[T : Equals](ts: T*) = {
    var set  = new EqualitySet[T] {
      def equality = implicitly[Equals[T]]
    }.empty
    ts.foreach { t => set += t }
    set
  }
}

然后,当我们使用上面的代码时,我们得到:

scala> val set = EqualitySet[Coordinate](Coordinate(-1,2),Coordinate(-1,3),Coordinate(1,4))

set: java.lang.Object with test.EqualitySet[Coordinate] = 
     Set(Coordinate(-1,2)
         Coordinate(1,4))

scala> val set2 = set.filter(_.i > 0)

// still an EqualitySet[Coordinate] o/ */
set2: test.EqualitySet[Coordinate] = Set(Coordinate(1,4))

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读