scala – 订购和TreeMap

我正在构建一个MultiSet [A]并使用TreeMap [A​​,Int]来跟踪元素.

class MultiSet[A <: Ordered[A] ](val tm: TreeMap[A,Int]) { ... }

现在我想使用这个框架创建一个MultiSet [Int].特别是,我想要一个方法,它将采用Vector [Int]并生成一个TreeMap [Int,Int],我可以用它来创建一个MultiSet [Int].

我写了下面的vectorToTreeMap,它编译时无怨无悔.

def vectorToTreeMap[A <: Ordered[A]](elements: Vector[A]): TreeMap[A,Int] =
  elements.foldLeft(new TreeMap[A,Int]())((tm,e) => tm.updated(e,tm.getOrElse(e,0) + 1))

但是,当我尝试

val tm: TreeMap[Int,Int] = vectorToTreeMap(Vector(1,2,3))

我收到编译器投诉说Int不符合A<:Ordered [A].在此上下文中创建TreeMap [Int,Int]需要什么? (我想要更一般的情况,因为MultiSet [A]并不总是MultiSet [Int].) 我也试过A<:scala.math.Ordered [A]和A&lt ;: Ordering [A]但没有更好的结果. (我承认我不理解三种可能性之间的差异以及在这种情况下是否重要.) 谢谢你的帮助.

解决方法

问题是Int是java int的别名,它不实现Ordered [Int].怎么可能呢,因为java甚至都不知道Ordered [T]特征存在.

有两种方法可以解决您的问题:

查看范围:

第一种方法是将约束<:更改为视图绑定<%.

def vectorToTreeMap[A <% Ordered[A]](elements: Vector[A]): TreeMap[A,0) + 1))

A&lt ;:Ordered [A]意味着方法vectorToTreeMap仅为直接实现Ordered [A]的类型定义,它排除了Int.

<%Ordered [A]意味着为所有“可被视为”实现Ordered [A]的类型定义了vectorToTreeMap方法,其中包括Int,因为存在从Int到Ordered [Int]定义的隐式转换:

scala> implicitly[Int => Ordered[Int]]
res7: Int => Ordered[Int] = <function1>

输入类

第二种方法是不要求类型A的任何(直接或间接)继承关系,但只要求存在一种方法来订购类型A的实例.

基本上,您总是需要一个能够从向量创建TreeMap的排序,但是为了避免在每次调用方法时都必须传递它,您将使排序成为隐式参数.

def vectorToTreeMap[A](elements: Vector[A])(implicit ordering:Ordering[A]): TreeMap[A,0) + 1))

事实证明,对于所有java原始类型以及String都存在Ordering [A]的实例,正如您可以在scala REPL中使用隐式方法看到的:

scala> implicitly[Ordering[Int]]
res8: Ordering[Int] = scala.math.Ordering$Int$@5b748182

Scala甚至可以导出复合类型的排序.例如,如果你有一个元组,其中存在每个元素类型的排序,scala将自动提供元组类型的排序:

scala> implicitly[Ordering[(Int,Int)]]
res9: Ordering[(Int,Int)] = scala.math.Ordering$$anon$11@66d51003

使用所谓类型类的第二种方法更灵活.例如,如果您想要一个普通旧的int树,但是具有相反的顺序,那么您所要做的就是直接或作为隐式val提供反向int排序.

这种方法在惯用语中也很常见.所以甚至有特殊的语法:

def vectorToTreeMap[A : Ordering](elements: Vector[A]): TreeMap[A,Int] = ???

相当于

def vectorToTreeMap[A](elements: Vector[A])(implicit ordering:Ordering[A]): TreeMap[A,Int] = ???

它基本上意味着您希望方法vectorToTreeMap仅针对存在排序的类型定义,但您不关心为排序命名.即使使用短语法,您也可以将vectorToTreeMap与隐式求解的Ordering [A]一起使用,或者明确地传递Ordering [A].

第二种方法有两大优点:

>它允许您为不“拥有”的类型定义功能.
>它允许你解耦某些方面的行为,例如从类型本身排序,而使用继承方法,您将行为耦合到类型.例如,您可以为Sting提供正常的Ordering和caseInsensitiveOrdering.但是如果你让String从Ordered扩展,你必须决定一个排序行为.

这就是为什么在scala集合本身中使用第二种方法来提供TreeMap的排序.

编辑:这是一个为没有一个类型的类型提供排序的示例:

scala> case class Person(name:String,surname:String)
defined class Person

scala> implicitly[Ordering[Person]]
<console>:10: error: No implicit Ordering defined for Person.
              implicitly[Ordering[Person]]
                        ^

案例类没有自动定义的排序.但我们可以很容易地定义一个:

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Person(name:String,surname:String)

object Person {

  // just convert to a tuple,which is ordered by the individual elements
  val nameSurnameOrdering : Ordering[Person] = Ordering.by(p => (p.name,p.surname))

  // make the nameSurnameOrdering the default that is in scope unless something else is specified
  implicit def defaultOrdering = nameSurnameOrdering
}

// Exiting paste mode,now interpreting.

defined class Person
defined module Person

scala> implicitly[Ordering[Person]]
res1: Ordering[Person] = scala.math.Ordering$$anon$9@50148190

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...