如何从列表中删除重复项,然后按最频繁排序

时间:2013-02-24 06:33:08

标签: scala

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

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

8 个答案:

答案 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)