【问题标题】:Scala 2.8 TreeMap and custom OrderingScala 2.8 TreeMap 和自定义排序
【发布时间】:2010-04-21 14:35:56
【问题描述】:

我正在从 scala 2.7 切换并订购到 scala 2.8 并使用订购。它看起来很简单,但我想知道我能否让它不那么冗长。例如:

scala> case class A(i: Int)
defined class A
scala> object A extends Ordering[A] { def compare(o1: A, o2: A) = o1.i - o2.i}
defined module A

如果我随后尝试创建 TreeMap,则会收到错误消息

scala> new collection.immutable.TreeMap[A, String]()
<console>:10: error: could not find implicit value for parameter ordering: Ordering[A]
       new collection.immutable.TreeMap[A, String]()
       ^

但是,如果我将对象 A 明确指定为排序,它就可以正常工作。

scala> new collection.immutable.TreeMap[A, String]()(A)
res34: scala.collection.immutable.TreeMap[A,String] = Map()

我是否总是必须明确指定顺序,还是有更短的格式?

谢谢

【问题讨论】:

  • 警告:通过减去整数来比较整数不起作用。也适用于此处给出的大多数答案。 stackoverflow.com/questions/2728793/…
  • ... iff 整数是 big 并且具有相反的符号。由于符号切换,该数字可能会溢出,从而产生相反的结果。但是,如果您使用的数字 接近Int.MAX_VALUE,那么您已经在玩火了,不是吗?我认为减法“成语”在 scala 中特别简洁/有用,因为 scala 没有(三元)条件表达式 (?:)
  • @kornfridge Scala 确实有条件表达式。语法是: if( condition ) valueIfTrue else valueIfFalse 。现在,如果使用符号? and : 而不是 "if(" 和 ") else" 是一个要求,那么不,Scala 没有条件表达式。

标签: scala scala-2.8 treemap


【解决方案1】:

请注意,创建Ordering 的方式稍微不那么冗长:

implicit val OrderingA = Ordering.by((_: A).i)

Ordering 的主要优点是您可以为同一类提供其中的许多。如果您的 A 类确实是 Ordered,那么您应该扩展它。如果没有,您可以显式传递 Ordering,而不是使用隐式:

new collection.immutable.TreeMap[A, String]()(Ordering.by(_.i))

【讨论】:

  • 看起来简洁、易懂、灵活。
  • 再次来到这里,想投票/评论但是..我已经在那里做了!
  • @Daniel,您将如何为具有多个字段的密钥实现该功能?例如。 case class A (i : Int, j : Int)。可以写..Ordering.by((_: A).i)..Ordering.by((_: A).j),但我找不到任何同时使用的选项。没有thenBy。元组也不起作用...有什么建议吗?
  • @Dan 当然有。有一个orElse 可以满足您的需求。当时还不存在。
【解决方案2】:

请注意诊断中的“隐式”一词。该参数声明为implicit,这意味着编译器将在您调用构造函数时尝试在范围内找到合适的值。如果您将 Ordering 设置为隐式值,则编译器将有资格进行此处理:

scala> implicit object A extends Ordering[A] { def compare(o1: A, o2: A) = o1.i - o2.i}
defined module A

scala> val tm1 = new collection.immutable.TreeMap[A, String]()
tm1: scala.collection.immutable.TreeMap[A,String] = Map()

编辑:

该示例在 REPL 中有效,因为 REPL 将您的代码包含在不可见的类定义中。这是一个独立工作的:

case class A(val i:Int) extends Ordered[A] { def compare(o:A) = i - o.i }

object A { implicit object AOrdering extends Ordering[A] { def compare(o1: A, o2: A) = o1.i - o2.i } }

class B {
    import A.AOrdering

    val tm1 = new collection.immutable.TreeMap[A, String]()
}

【讨论】:

  • 如果我在我的代码中尝试这样做,我会被告知“错误:‘隐式’修饰符不能用于顶级对象”。那么有没有办法为顶级对象做到这一点?
  • @Dave 没有,但是您可以在包含 A 的包的包对象中放置这样的隐式。
  • @Daniel:你试过了吗?我做了,但不知何故被编译器拒绝了。我不知道是我做错了还是真的不允许。
  • 我没有尝试包对象解决方案。其他都还好。
  • @Dave 实际上,将implicit object AOrdering 替换为对象伴侣(即object A)。这似乎也有效。
【解决方案3】:

不要扩展Ordering[A],而是尝试扩展Ordered[A]。像这样:

scala> case class A(val i:Int) extends Ordered[A] {def compare(o:A) = i-o.i}
defined class A

scala> A(1)<A(2)
res0: Boolean = true

scala> A(1)<A(0)
res1: Boolean = false

scala> new collection.immutable.TreeMap[A, String]()
res3: scala.collection.immutable.TreeMap[A,String] = Map()

【讨论】:

  • 工作方式是低优先级隐式将 Ordered[A] 转换为 TreeMap 的 Ordering[A]。不幸的是,我们将 TreeMaps 序列化以进行存储,并且排序的类有点不稳定(一些 $$anon$ 类)。
猜你喜欢
  • 1970-01-01
  • 2016-02-23
  • 2017-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多