找到集合中最常见/最常见的元素?

时间:2012-12-14 11:47:58

标签: list scala

找到集合中最常见/最常见元素的最佳方法是什么?例如:

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

嗯..我们可以做的是首先groupBymap length,然后选择最大的一个。{1}}。那么你会得到:

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

最后,选择映射到最高编号(4)的密钥(2)。 (嵌套问题:最好的方法是什么?)。但这对于这么简单的操作来说似乎有很多工作要做..?

有更好/更惯用的方法吗?

5 个答案:

答案 0 :(得分:22)

我必须说:

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

这显然比上面的单行程要差得多,所以我建议坚持使用它们,除非你能表明它们是你应用程序中的瓶颈(即基准测试,而不是猜测)。 / p>

答案 1 :(得分:2)

我认为这不是更好,但你可以这样做:

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

不是最好的解决方案。你想要的是在列表中使用maxBy然后像这样引用列表的一些方法:

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

答案 2 :(得分:1)

不,我认为这是最好的方式。但这不是很多工作......

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

给你

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

然后,例如,您可以使用.maxBy(_._2)(编辑:感谢@Travis Brown!)并获得一个元组(4,2)(出现次数最多的次数和发生的次数)

如果你是单行的粉丝:

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

答案 3 :(得分: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

答案 4 :(得分:0)

Scala 2.13开始,我们可以使用:

List(1, 3, 4, 4, 2, 3).groupMapReduce(identity)(_ => 1)(_+_).maxByOption(_._2).map(_._1)
// Option[Int] = Some(4)

此:

  • group的项目( MapReduce的组部分)

  • map将每个分组值出现的次数设为1(组 Map Reduce的映射部分)

  • reduce在一组值(_ + _)中的值相加(减少groupMap Reduce 的一部分)。

  • 最终通过nbr次出现获得可选的最大值,并将其映射为对应的项。


如果您知道列表不为空,那么简单的maxBy也可以:

List(1, 3, 4, 4, 2, 3).groupMapReduce(identity)(_ => 1)(_+_).maxBy(_._2)._1
// 4

groupMapReduce部分是以下顺序的等效版本performed in one pass

List(1, 3, 4, 4, 2, 3).groupBy(identity).mapValues(_.map(_ => 1).reduce(_+_))