我有一个包含可能重复的各种关键字的列表。我需要生成一个具有不同关键字的列表,但按它们在原始列表中出现的频率排序。
惯用的 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")
我有一个包含可能重复的各种关键字的列表。我需要生成一个具有不同关键字的列表,但按它们在原始列表中出现的频率排序。
惯用的 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")
较短的版本:
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)
评论无法修复的实现没有错!说真的,把它分解一下,描述你采取每一步的原因和原因。
也许不是“简洁”,但 scala 中简洁代码的目的是使代码更具可读性。当简洁的代码不清楚时,是时候备份、分解(引入命名良好的局部变量)和注释了。
这是我的看法,不知道它是否不那么“丑陋”:
scala> keys.groupBy(p => p).values.toList.sortBy(_.size).reverse.map(_.head)
res39: List[String] = List(a, b, c)
折叠版:
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 }
怎么样:
keys.distinct.sorted
新手没有仔细阅读问题。让我再试一次:
keys.foldLeft (Map[String,Int]()) { (counts, elem) => counts + (elem -> (counts.getOrElse(elem, 0) - 1))}
.toList.sortBy(_._2).map(_._1)
如果您愿意,可以使用可变 Map。负频率计数存储在地图中。如果这让您感到困扰,您可以将它们设为正数并否定 sortBy 参数。
也许,
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)
与@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)
我喜欢的版本是:
最规范/最具表现力?
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)