scala - Groupby 类似于 Python 的 itertools.groupby

标签 scala scala-collections

在 Python 中,我可以使用 itertools.groupby 将具有相同键的连续元素分组。 :

>>> items = [(1, 2), (1, 5), (1, 3), (2, 9), (3, 7), (1, 5), (1, 4)]
>>> import itertools
>>> list(key for key,it in itertools.groupby(items, lambda tup: tup[0]))
[1, 2, 3, 1]

Scala 也有 groupBy,但它会产生不同的结果 - 一个从键指向在具有指定键的可迭代对象中找到的所有值的映射(而不是使用相同键的连续运行):

scala> val items = List((1, 2), (1, 5), (1, 3), (2, 9), (3, 7), (1, 5), (1, 4))
items: List[(Int, Int)] = List((1,2), (1,5), (1,3), (2,9), (3,7), (1,5), (1,4))

scala> items.groupBy {case (key, value) => key}
res0: scala.collection.immutable.Map[Int,List[(Int, Int)]] = Map(2 -> List((2,9)), 1 -> List((1,2), (1,5), (1,3), (1,5), (1,4)), 3 -> List((3,7)))

实现与 Python itertools.groupby 相同的最 Eloquent 方法是什么?

最佳答案

如果你只是想扔掉连续的重复项,你可以这样做:

def unchain[A](items: Seq[A]) = if (items.isEmpty) items else {
  items.head +: (items zip items.drop(1)).collect{ case (l,r) if r != l => r }
}

也就是说,只需将列表与自身移动一个位置的版本进行比较,只保留不同的项目。很容易向方法添加 (same: (a1: A, a2: A) => Boolean) 参数并使用 !same(l,r) 如果你想要相同的自定义行为(例如,只需按键即可)。

如果你想保留重复项,你可以使用 Scala 的 groupBy 来获得一个非常紧凑(但效率低下)的解决方案:

def groupSequential(items: Seq[A])(same: (a1: A, a2: A) => Boolean) = {
  val ns = (items zip items.drop(1)).
    scanLeft(0){ (n,cc) => if (same(cc._1, cc._2)) n+1 else n }
  (ns zip items).groupBy(_._1).toSeq.sortBy(_._1).map(_._2)
}

关于scala - Groupby 类似于 Python 的 itertools.groupby,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24512600/

相关文章:

scala - 使用压缩集合在 Scala 中初始化案例类

scala - 如何使用 CanBuildFrom 为 Traversable 定义隐式类?

Map[..] 上的 Scala map() 比 mapValues() 慢得多

scala - 如何从 spark 中的输出控制台抑制 "Stage 2===>"?

java - 在Scala中使用Scala内核

json - 在 Play 中将 Seq 映射到 JSON

scala 将 Iterator[Option[T]] 转换为 Iterator[T]

java - 如何使用 Scala 的 GraphStream 库

scala - 如何用trait来描述算子?

scala - Spark Dataframe 上的 val 与 def 性能