如何根据某些文本标准对元组列表进行分组/存储?

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】:

使用enumeratezipiter函数的解决方案:

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) 呈现)并创建一个包含两个项目的元组,这些项目指向从startend 的索引(连续)

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)

【讨论】:

以上是关于如何根据某些文本标准对元组列表进行分组/存储?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据另一个列表对元组列表进行排序

如何根据另一个列表中元组元素的顺序对元组列表进行排序?

根据元组的值对元组列表中的重复元组进行平均

根据第三个参数对元组列表进行排序[重复]

根据元组的值,以不同的顺序对元组列表进行排序。

如何按两个元素对元组列表进行排序?