3

我有一个包含可能重复的各种关键字的列表。我需要生成一个具有不同关键字的列表,但按它们在原始列表中出现的频率排序。

惯用的 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")
4

8 回答 8

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)
于 2013-02-24T06:48:15.873 回答
2

评论无法修复的实现没有错!说真的,把它分解一下,描述你采取每一步的原因和原因。

也许不是“简洁”,但 scala 中简洁代码的目的使代码更具可读性。当简洁的代码不清楚时,是时候备份、分解(引入命名良好的局部变量)和注释了。

于 2013-02-24T06:45:00.503 回答
2

这是我的看法,不知道它是否不那么“丑陋”:

scala> keys.groupBy(p => p).values.toList.sortBy(_.size).reverse.map(_.head)
res39: List[String] = List(a, b, c)
于 2013-02-24T06:56:34.450 回答
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 }
于 2013-02-24T07:05:20.313 回答
0

怎么样:

keys.distinct.sorted

新手没有仔细阅读问题。让我再试一次:

keys.foldLeft (Map[String,Int]()) { (counts, elem) => counts + (elem -> (counts.getOrElse(elem, 0) - 1))}
    .toList.sortBy(_._2).map(_._1)

如果您愿意,可以使用可变 Map。负频率计数存储在地图中。如果这让您感到困扰,您可以将它们设为正数并否定 sortBy 参数。

于 2013-02-24T06:48:54.450 回答
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)
于 2013-02-24T07:11:08.360 回答
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)
于 2013-02-24T09:19:01.557 回答
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)
于 2015-10-02T21:28:33.927 回答