2012-12-14 9 views
10

コレクション内で最も頻繁に/共通の要素を見つける最良の方法は何ですか?たとえば:コレクション内で最も頻繁に/共通の要素を見つけることはできますか?

list = List(1, 3, 4, 4, 2) 
list.mostCommon // => 4  !! This is what I want !! 

うーん...何1が行う可能性はlengthによってそれらgroupBy最初にしmapを行い、その後、最大のものを選択することです。だから、あなたが得るでしょう:

Map(1 -> List(1), 4 -> List(4, 4), 3 -> List(3), 2 -> List(2)) 
(...) 
Map(1 -> 1, 4 -> 2, 3 -> 1, 2 -> 1) // mapped by length. 4 -> 2 since there's two 4s 

そして最後に、最大数(2)にマップキー(4)を選択します。 (ネストされた質問:これを行う最善の方法は何ですか?)しかし、それはそのような単純な操作のための多くの仕事のように思えます..?

これを行うにはより良い/より慣用的な方法がありますか?

+3

ネストされた答え: 'maxBy'を使用何が欲しいのは、リスト上のmaxByを使用して、そのようなリストを参照するためのいくつかの方法です。 – senia

+0

最大値が複数ある可能性があります。この場合、見つかった最大値でマップをフィルタリングできます。 –

答えて

20

私はそれを言っている:

list.groupBy(identity).mapValues(_.size).maxBy(_._2)._1 

それとも:

list.groupBy(identity).maxBy(_._2.size)._1 

は本当に私にはその多くの仕事のように見えるしていません。あなたが唯一のカウントを必要とするとき、各値のリストを構築するオーバーヘッド心配している場合は、次の操作を行うことができ

list.foldLeft(Map.empty[Int, Int].withDefaultValue(0)) { 
    case (m, v) => m.updated(v, m(v) + 1) 
}.maxBy(_._2)._1 

、あるいはあなたが行くように、最大​​の経過を追います最後に余分なトラバーサルを避けるために:

list.foldLeft(
    Map.empty[Int, Int].withDefaultValue(0), -1 -> Double.NegativeInfinity 
) { 
    case ((m, (maxV, maxCount)), v) => 
    val count = m(v) + 1 
    if (count > maxCount) (m.updated(v, count), v -> count) 
    else (m.updated(v, count), maxV -> maxCount) 
}._2._1 

する。これは、しかし、明らかにはるかに少ない読める上記ワンライナーよりも、私はあなたが見ることができますしない限り、ベンチマーキングで、すなわち(彼らと一緒にいないこだわりのお勧めします投機的な)彼らはあなたのアプリケーションのボトルネックだ。

+0

'maxBy'の前に' toSeq'は必要ありません。 – senia

+0

@senia。ああ、確かに。編集されました。 –

1

いいえ、私はそれが最善の方法だと思います。しかし、それは多くの作業ではありません...

list.groupBy(identity).mapValues(_.size) 

はあなたに

Map(2 -> 1, 4 -> 2, 1 -> 2, 3 -> 1) 

を与え、その後、例えば、あなたがその.maxBy(_._2)(!EDITED:感謝@Travisブラウン)を取ることができ、タプルを取得(4,2)あなたはワンライナーのファンなら

(ほとんどの時間、それが発生した回数を発生回数):

scala> List(1, 3, 4, 1, 4, 2).groupBy(identity).mapValues(_.size).maxBy(_._2) 
res0: (Int, Int) = (4,2) 
+0

あなたの1ライナーはここでも動作します。なぜなら、 '4'もまた最大値になるからです。あなたは 'maxBy'が必要です(私の答えを見てください)。 –

+0

@TravisBrown:ありがとうございます! –

+0

あなたが提供するワンライナーは、このアプローチの欠陥を示しています。 1と4は両方とも最も頻繁な値ですが、4が与えられます。 –

2

は、私は、これは本当にどんな進歩していないと思いますが、あなたはこれを行うことができます:

List(1, 3, 4, 4, 2).groupBy(identity).maxBy(_._2.size)._1 

ない素敵なソリューションを。

val someList = List(1, 3, 4, 4, 2) 
someList.maxBy(x => list.count(_ == x)) 
+2

私はほとんどの場合、小さなパフォーマンス向上以上の読みやすさを選択するための提唱者ですが、私は副次的な問題の二次的な解決法は今まで良いアイデアであるか分からない。 –

0

別の変形:

val x = List(1, 3, 4, 1, 4, 2, 5, 5, 5) 
x.distinct.foldLeft((0,0))((a, b) => { 
    val cnt = x.count(_ == b); 
    if (cnt > a._1) (cnt, b) else a 
})._2 
関連する問題