在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
,但是它产生了不同的结果--一个从key指向在可迭代对象中找到的所有具有指定key的值的Map(而不是具有相同key的连续运行):
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
相同的最有说服力的方法?
6条答案
按热度按时间frebpwbc1#
如果你只是想丢弃连续的重复,你可以这样做:
也就是说,只需将列表与移位了一位的列表进行比较,并只保留不同的项。如果您希望自定义相同项的行为(例如,只通过键来执行),可以很容易地在方法中添加
(same: (a1: A, a2: A) => Boolean)
参数并使用!same(l,r)
。如果您想保留副本,可以使用Scala的
groupBy
来获得一个非常紧凑(但效率低下)的解决方案:cnh2zyt32#
使用
List.span
,如下所示因此让
所以
如@Paul所建议的更易读的语法、可能更简洁使用的隐式类和通用性的类型参数化,
因此,请按如下方式使用它,
jtoj6r0c3#
下面是一个简洁但效率低下的解决方案:
下面是一个更好的例子,它只对每个元素调用
f
一次:这两个解决方案都在
items
上折叠,在运行过程中建立了一个组列表。pythonGroupBy2
还跟踪当前组的f
值。最后,我们必须颠倒每个组和组列表,以获得正确的顺序。3htmauhk4#
试试看:
其中
compress
是其中一个99 Problems in Scala的解。w8ntj3qf5#
嗯,从盒子里找不到什么东西,但这个可以
现在您可以:
6qfn3psc6#
下面是我在工作中遇到的一个问题的简单解决方案。在这种情况下,我不太关心空间,所以不担心高效的迭代器。使用ArrayBuffer来累积结果。
(Don不要将此用于大量的数据。)
连续分组依据
运行上述代码会产生以下结果: