【问题标题】: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')]

【问题讨论】:

    标签: python list tuples itertools


    【解决方案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)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-11-14
          • 1970-01-01
          • 1970-01-01
          • 2022-01-23
          • 1970-01-01
          • 1970-01-01
          • 2020-09-15
          • 1970-01-01
          相关资源
          最近更新 更多