我有一个列表,其中包含可能重复的各种关键字。我需要生成一个包含不同关键字的列表,但按照它们出现在原始列表中的频率进行排序。
那个惯用的Scala怎么样?这是一个有效但丑陋的实现:
val keys = List("c","a","b","b","a","a")
keys.groupBy(p => p).toList.sortWith( (a,b) => a._2.size > b._2.size ).map(_._1)
// List("a","b","c")
答案 0 :(得分:8)
更短的版本:
keys.distinct.sortBy(keys count _.==).reverse
然而,这并不是特别有效。 groupBy
版本应该表现更好,但可以改进:
keys.groupBy(identity).toSeq.sortBy(_._2.size).map(_._1)
也可以通过声明reverse
来摆脱第一版中的Ordering
:
val ord = Ordering by (keys count (_: String).==)
keys.distinct.sorted(ord.reverse)
请注意,此版本中的reverse
只生成一个新的Ordering
,其工作方式与原始版本相反。此版本还提出了一种获得更好性能的方法:
val freq = collection.mutable.Map.empty[String, Int] withDefaultValue 0
keys foreach (k => freq(k) += 1)
val ord = Ordering by freq
keys.distinct.sorted(ord.reverse)
答案 1 :(得分:2)
评论无法修复的实现没有错! 说真的,把它分解一下并描述一下&为什么你要采取每一步。
可能不是“简洁”,但scala 中简洁代码的目的是,以使代码更具可读性。当简明的代码不清楚时,是时候备份,分解(引入命名良好的局部变量)和评论。
答案 2 :(得分:2)
这是我的看法,不知道它是不是“丑陋”:
scala> keys.groupBy(p => p).values.toList.sortBy(_.size).reverse.map(_.head)
res39: List[String] = List(a, b, c)
答案 3 :(得分:1)
折叠版:
val keys = List("c","a","b","b","a","a")
val keysCounts =
(Map.empty[String, Int] /: keys) { case (counts, k) =>
counts updated (k, (counts getOrElse (k, 0)) + 1)
}
keysCounts.toList sortBy { case (_, count) => -count } map { case (w, _) => w }
答案 4 :(得分:0)
怎么样:
keys.distinct.sorted
新手没有仔细阅读这个问题。让我再试一次:
keys.foldLeft (Map[String,Int]()) { (counts, elem) => counts + (elem -> (counts.getOrElse(elem, 0) - 1))}
.toList.sortBy(_._2).map(_._1)
如果您愿意,可以使用可变地图。负频率计数存储在地图中。如果这困扰你,你可以使它们变为正面并否定sortBy参数。
答案 5 :(得分:0)
也许,
val mapCount = keys.map(x => (x,keys.count(_ == x))).distinct
// mapCount : List[(java.lang.String, Int)] = List((c,1), (a,3), (b,2))
val sortedList = mapCount.sortWith(_._2 > _._2).map(_._1)
// sortedList : List[java.lang.String] = List(a, b, c)
答案 6 :(得分:0)
与@Daniel的第4版略有不同,可能会有更好的表现:
scala> def sortByFreq[T](xs: List[T]): List[T] = {
| val freq = collection.mutable.Map.empty[T, Int] withDefaultValue 0
| xs foreach (k => freq(k) -= 1)
| xs.distinct sortBy freq
| }
sortByFreq: [T](xs: List[T])List[T]
scala> sortByFreq(keys)
res2: List[String] = List(a, b, c)
答案 7 :(得分:0)
我的首选版本是:
大多数规范/表达?
keys.groupBy(identity).toList.map{ case (k,v) => (-v.size,k) }.sorted.map(_._2)
最短,可能效率最高?
keys.groupBy(identity).toList.sortBy(-_._2.size).map(_._1)
直接前进
keys.groupBy(identity).values.toList.sortBy(-_.size).map(_.head)