分享

Scala的map实现key和value排序及各种排序比较等知识讨论

问题导读

1.map能否直接排序?
2.如何转换,才能排序?
3.排序结果可以存储在哪两个集合中?
4._*如何使用?
5.排序函数中,哪个可以进行升序和降序排列?
6.他们的排序性能如何?





如过想要对一个map排序,该如何实现。

首先给一个不可变的map
[mw_shl_code=scala,true]scala> val grades = Map("Kim" -> 90,
     |     "Al" -> 85,
     |     "Melissa" -> 95,
     |     "Emily" -> 91,
     |     "Hannah" -> 92
     | )
grades: scala.collection.immutable.Map[String,Int] = Map(Hannah -> 92, Melissa -> 95, Kim -> 90, Emily -> 91, Al -> 85)[/mw_shl_code]
scala.jpg

你可以按照value排序,从高到低,使用sortBy

[mw_shl_code=scala,true]scala> import scala.collection.immutable.ListMap
import scala.collection.immutable.ListMap

scala> ListMap(grades.toSeq.sortBy(_._2):_*)
res0: scala.collection.immutable.ListMap[String,Int] = Map(Al -> 85, Emily -> 91, Hannah -> 92, Kim -> 90, Melissa -> 95)[/mw_shl_code]

当然你也可以按照名字排序,也就是key排序,但是key排序显然作用不大。
[mw_shl_code=scala,true]scala> ListMap(grades.toSeq.sortBy(_._1):_*)[/mw_shl_code]
1.jpg

上面是使用sortBy,下面我们使用sortWith

从低到高排序
[mw_shl_code=scala,true]scala> ListMap(grades.toSeq.sortWith(_._2<_._2):_*)
res2: scala.collection.immutable.ListMap[String,Int] = Map(Al -> 85, kim -> 90,
Emily -> 91, Hannah -> 92, Melissa -> 95)[/mw_shl_code]

从高到低排序
[mw_shl_code=scala,true]scala> ListMap(grades.toSeq.sortWith(_._2>_._2):_*)
res3: scala.collection.immutable.ListMap[String,Int] = Map(Melissa -> 95, Hannah
-> 92, Emily -> 91, kim -> 90, Al -> 85)[/mw_shl_code]

排序.jpg


上面所有的例子,都不是使用map直接排序,而是使用sort函数,结果在一个新的已经排序的map中,输出结果需要一个新的变量。
因此你可以使用ListMap 或则LinkedHashMap ,下面使用的是LinkedHashMap .
[mw_shl_code=scala,true]scala> val x=collection.mutable.LinkedHashMap(grades.toSeq.sortBy(_._2):_*)
x: scala.collection.mutable.LinkedHashMap[String,Int] = Map(Al -> 85, kim -> 90,
Emily -> 91, Hannah -> 92, Melissa -> 95)

scala> x.foreach(println)
(Al,85)
(kim,90)
(Emily,91)
(Hannah,92)
(Melissa,95)[/mw_shl_code]


linkhashmap.jpg
讨论与思考:

对于一个map
[mw_shl_code=scala,true]scala> val grades = Map("Kim" -> 90,
     |     "Al" -> 85,
     |     "Melissa" -> 95,
     |     "Emily" -> 91,
     |     "Hannah" -> 92
     | )
grades: scala.collection.immutable.Map[String,Int] = Map(Hannah -> 92, Melissa -> 95, Kim -> 90, Emily -> 91, Al -> 85)[/mw_shl_code]
我们为什么要把他转换为序列toSeq
[mw_shl_code=scala,true]grades.toSeq[/mw_shl_code]
因为map没有排序函数,所以我们转换序列后,可以使用排序函数
[mw_shl_code=scala,true]grades.toSeq.sortBy(_._2)[/mw_shl_code]
[mw_shl_code=scala,true]grades.toSeq.sortWith(_._2 < _._2)[/mw_shl_code]

数据排序后,会存储在ListMap 中
[mw_shl_code=scala,true]ListMap(grades.toSeq.sortBy(_._2):_*)[/mw_shl_code]

LinkedHashMap 也存储排序后的数据,如下
[mw_shl_code=scala,true]import scala.collection.mutable.LinkedHashMap[/mw_shl_code]
[mw_shl_code=scala,true]LinkedHashMap(grades.toSeq.sortBy(_._2):_*)[/mw_shl_code]

有可变和不可变的listMap版本,LinkedHashMap 只是一个可变的类,是比较好的解决方案。

关于排序函数中 _*的含义
整体来说,他可以代表多个参数,详细可参考下面说明
_*他可以传递或则代表多个参数,比如 ListMap 或则LinkedHashMap. 你不能直接初始化ListMap 使用tuples序列,但是apply 方法在伴生对象接受Tuple2 变参数,可以使用x和它一起,如下面例子
[mw_shl_code=scala,true]scala> ListMap(x: _*)
[/mw_shl_code]
create.jpg
尝试创建ListMap不使用上面方式
[mw_shl_code=scala,true]ListMap(x)[/mw_shl_code]

listmap错误创建.jpg

另外一种方式, 自定义函数,使用可变参数,_*它是如何使用的。下面printAll ,需要一个参数,和一个可变参数的String类型。
[mw_shl_code=scala,true]def printAll(strings: String*) {
    strings.foreach(println)
}[/mw_shl_code]
你可以创建list如下

list.jpg

上面我们使用printAll(fruits)出错,我们可以这样使用
[mw_shl_code=scala,true]printAll(fruits: _*)
[/mw_shl_code]

打印.jpg

排序性能
额外补充他们的排序性.这里就不在过多说明,可参考下图

排序性能.png







本帖被以下淘专辑推荐:

已有(3)人评论

跳转到指定楼层
monik 发表于 2017-10-23 08:35:58
楼主大牛一只,鉴定完毕!
回复

使用道具 举报

霍普夫是只树懒 发表于 2017-12-19 16:48:16
学习了, sortBy 可以从大到小排序吗
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条