如何使用itertools.groupby()获取每个项的索引和出现次数
这是我的故事,我有两个列表:
list_one=[1,2,9,9,9,3,4,9,9,9,9,2]
list_two=["A","B","C","D","A","E","F","G","H","Word1","Word2"]
我想找到第一个列表中连续出现的9的索引,这样我就可以从第二个列表中获取对应的字符串。我尝试过:
group_list_one= [(k, sum(1 for i in g),pdn.index(k)) for k,g in groupby(list_one)]
我本来希望能找到每个元组中第一个9的索引,然后再从那里继续,但这并没有成功……
我该怎么做呢?
附注:我看过itertools的文档,但对我来说似乎很模糊……
提前谢谢你!
编辑:
我期望的输出是(键,出现次数,第一个出现的索引),类似于:
[(9, 3, 2), (9, 4, 7)]
4 个回答
这个问题看起来太复杂,不适合用列表推导式来处理。
element_index = 0 #the index in list_one of the first element in a group
for element, occurrences in itertools.groupby(list_one):
count = sum(1 for i in occurrences)
yield (element, count, element_index)
element_index += count
如果你想去掉 element_index
这个变量,可以考虑一下一个累加和函数需要做什么,它的值是依赖于之前所有已经计算过的值的。
好吧,这可能不是最优雅的解决方案,但我来试试:
g = groupby(enumerate(list_one), lambda x:x[1])
l = [(x[0], list(x[1])) for x in g if x[0] == 9]
[(x[0], len(x[1]), x[1][0][0]) for x in l]
这段代码的结果是
[(9, 3, 2), (9, 4, 7)]
好吧,我有一个一行解决方案。虽然看起来有点丑,但请耐心听我讲。
先来看看这个问题。我们有一个列表,想用itertools.groupby来计算总和。groupby会给我们一组键和它们重复的次数。在这个阶段,我们无法计算索引,但我们可以轻松找到每个元素出现的次数。
[(key, len(list(it))) for (key, it) in itertools.groupby(list_one)]
现在,真正的问题是我们想要根据之前的数据来计算索引。在大多数一行的常用函数中,我们只关注当前的状态。然而,有一个函数可以让我们回顾过去,那就是reduce
。
reduce
的作用是遍历迭代器,并用上一个函数的结果和新项来执行一个函数。例如,reduce(lambda x,y: x*y, [2,3,4])
会先计算2乘以3等于6,然后再计算6乘以4等于24,最后返回24。此外,你还可以选择一个不同的初始值来代替第一个项。
我们在这里使用它——对于每个项,索引将是上一个索引加上上一个出现的次数。为了得到一个有效的列表,我们将使用[(0,0,0)]作为初始值。(最后我们会把它去掉)。
reduce(lambda lst,item: lst + [(item[0], item[1], lst[-1][1] + lst[-1][-1])],
[(key, len(list(it))) for (key, it) in itertools.groupby(list_one)],
[(0,0,0)])[1:]
如果我们不想添加初始值,我们可以把到目前为止出现的次数加起来。
reduce(lambda lst,item: lst + [(item[0], item[1], sum(map(lambda i: i[1], lst)))],
[(key, len(list(it))) for (key, it) in itertools.groupby(list_one)], [])
当然,这样会给我们所有的数字。如果我们只想要9,我们可以把整个过程放在filter
里面:
filter(lambda item: item[0] == 9, ... )
根据你期望的输出结果,可以试试这个:
from itertools import groupby
list_one=[1,2,9,9,9,3,4,9,9,9,9,2]
list_two=["A","B","C","D","A","E","F","G","H","Word1","Word2"]
data = zip(list_one, list_two)
i = 0
out = []
for key, group in groupby(data, lambda x: x[0]):
number, word = next(group)
elems = len(list(group)) + 1
if number == 9 and elems > 1:
out.append((key, elems, i))
i += elems
print out
输出结果:
[(9, 3, 2), (9, 4, 7)]
但是如果你真的想要这样的输出:
[(9, 3, 'C'), (9, 4, 'G')]
那么看看这个代码片段:
from itertools import groupby
list_one=[1,2,9,9,9,3,4,9,9,9,9,2]
list_two=["A","B","C","D","A","E","F","G","H","Word1","Word2"]
data = zip(list_one, list_two)
out = []
for key, group in groupby(data, lambda x: x[0]):
number, word = next(group)
elems = len(list(group)) + 1
if number == 9 and elems > 1:
out.append((key, elems, word))
print out