找到集合中最常见/最常见元素的最佳方法是什么?例如:
list = List(1, 3, 4, 4, 2)
list.mostCommon // => 4 !! This is what I want !!
嗯..我们可以做的是首先groupBy
再map
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
)。 (嵌套问题:最好的方法是什么?)。但这对于这么简单的操作来说似乎有很多工作要做..?
有更好/更惯用的方法吗?
答案 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::groupMapReduce
,顾名思义,它等效于groupBy
,后跟mapValues
和缩减步骤。Map::maxByOption
而不是简单的maxBy
来处理空列表: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(_+_))