如何根据某些文本标准对元组列表进行分组/存储?
Posted
技术标签:
【中文标题】如何根据某些文本标准对元组列表进行分组/存储?【英文标题】:How to group/bucket a list of tuples based on certain text criteria? 【发布时间】:2016-11-23 20:02:59 【问题描述】:我有一个元组列表,其中一些元组将“开始”和“结束”作为元组中的第一项。我想将元组列表存储到元组列表中,其中子列表按它们是否位于第一项中具有“开始”的元组和第一项中的“结束”之间进行分组。
list = [('start',1),('item_1',4),('item_2',2),('end',1),('start',10),('item_1',5),('item_3',2),('end',1),('start',10),('item_1',5),('item_3',2),('item_3',9),('end',1)]]
desired_result = [[('start',1),('item_1',4),('item_2',2),('end',1)],[('start',10),('item_1',5),('item_3',2),('end',1)],[('start',10),('item_1',5),('item_3',9),('item_3',2),('end',1)]]
我正在尝试使用 groupby 和 itemgetter,但收效甚微:
from operator import itemgetter
from itertools import groupby
[list(group) for key, group in itertools.groupby(sorted(list), itemgetter('start','end')]
【问题讨论】:
【参考方案1】:不需要额外的模块。
我猜想“end”后面跟着“start”,所以不用找“end”了。
只计算包含"start"
的项目的索引
indexes = [i for i,e in enumerate(lst) if e[0]=='start']
然后使用切片构建子列表,最后一个元素的特殊情况包括最后一个列表
result = [lst[indexes[i]:indexes[i+1] if i<len(indexes)-1 else len(lst)] for i in range(len(indexes))]
结果:
[[('start', 1), ('item_1', 4), ('item_2', 2), ('end', 1)], [('start', 10), ('item_1', 5), ('item_3', 2), ('end', 1)], [('start', 10), ('item_1', 5), ('item_3', 2), ('item_3', 9), ('end', 1)]]
这是desired_result
,除了物品顺序,但我尊重原始列表顺序,因此您的预期结果中一定是错字
【讨论】:
【参考方案2】:使用enumerate
、zip
和iter
函数的解决方案:
list1 = [('start',1),('item_1',4),('item_2',2),('end',1),('start',10),('item_1',5),('item_3',2),('end',1),('start',10),('item_1',5),('item_3',2),('item_3',9),('end',1)]
grouped_list = [list1[r[0]:r[1]+1]
for r in list(zip(*[iter([k for k,t in enumerate(list1)
if t[0] in ('start','end')])] * 2))]
print(grouped_list)
输出:
[[('start', 1), ('item_1', 4), ('item_2', 2), ('end', 1)], [('start', 10), ('item_1', 5), ('item_3', 2), ('end', 1)], [('start', 10), ('item_1', 5), ('item_3', 2), ('item_3', 9), ('end', 1)]]
详情:
zip(*[iter(sequence)] * n))
将从迭代器中拉出一个项目(以iter(sequence)
呈现)并创建一个包含两个项目的元组,这些项目指向从start
到end
的索引(连续)
list1[r[0]:r[1]+1]
将获得每个start
-end
边界范围的项目切片
【讨论】:
【参考方案3】:itertools.groupby
是一个排序函数。这对你没有帮助。可能最好的方法是手动完成:
new_list = []
for item in old_list:
if item[0] == 'start':
new_list.append([item])
else:
new_list[-1].append(item)
请注意,如果第一个元组不是启动器,它将出错。它还将忽略结束点,因此任何不在 start 和 end 之间的元组都将添加到与最后一个 end 相同的列表中。如果你想捕捉所有可能存在的问题,那就有点复杂了:
new_list = []
in_list = False
for item in old_list:
if item[0] == 'start':
if in_list:
raise ValueError("The last list hasn't completed yet.")
new_list.append([item])
in_list = True
else:
if item[0] == 'end':
if not in_list:
raise ValueError("The list has already completed.")
in_list = False
# If this is a problem, it will throw its own error
new_list[-1].append(item)
【讨论】:
以上是关于如何根据某些文本标准对元组列表进行分组/存储?的主要内容,如果未能解决你的问题,请参考以下文章