2013-02-24 101 views
2

我有一個列表,包含可能重複的各種關鍵字。我需要生成具有不同關鍵字的列表,但按照它們出現在原始列表中的頻率排序。如何從列表中刪除重複項,然後按最頻繁排序

這將是怎樣的習慣斯卡拉?這是一個工作但醜陋的實現:

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

爲什麼醜嗎? – Rogach 2013-02-24 06:43:58

+0

好吧,這感覺就像是有更合適的功能,我錯過了,如摺疊或聚合,將用於使其更清晰。 – 2013-02-24 06:46:58

+1

如果有一個groupBy的變體,你可以傳遞一個函數來說明如何將下一個值合併/摺疊到分組鍵中是否有用?有任何數量的問題/答案在這裏它是groupBy +映射在它的價值陷入所需的結果... – 2013-02-24 11:30:21

回答

7

較短的版本:

keys.distinct.sortBy(keys count _.==).reverse 

但是這並不是特別有效。該groupBy版本應該有更好的表現,但它可以改進:

keys.groupBy(identity).toSeq.sortBy(_._2.size).map(_._1) 

人們也可以在第一時間拿到的版本通過聲明Ordering擺脫reverse的:

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) 
+0

很好找出關於身份:) – 2013-02-25 14:32:57

2

沒有錯,那個註釋無法修復的實現! 說真的,把它分解一點,並描述你爲什麼要採取每一步。

也許不是「簡潔」,但scala 簡潔代碼的目的是使代碼更具可讀性。當簡明代碼不清晰時,應該備份,分解(引入命名的局部變量)和註釋。

0

如何:

keys.distinct.sorted 

新手沒仔細看這個問題。讓我再試一次:

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

如果您願意,可以使用可變映射。負頻率計數存儲在地圖中。如果這讓你感到困擾,你可以讓它們變得積極,並且否定這種討論。

+1

這將按字母順序排序字符串。 – 2013-02-24 06:50:32

2

這裏是我拿的,不知道,如果它是不那麼 「醜」:

scala> keys.groupBy(p => p).values.toList.sortBy(_.size).reverse.map(_.head) 
res39: List[String] = List(a, b, c) 
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 } 
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) 
0

距離變化不大@丹尼爾的第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) 
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) 
相關問題