【问题标题】:Splitting a list based on change in value using itertools使用 itertools 根据值的变化拆分列表
【发布时间】:2019-04-18 15:07:26
【问题描述】:

我有一个列表,我试图按值的变化进行分组:

input_list = ["I", "Non-I", "Non-I", "Non-I", "I", "Non-I", "Non-I", "Non-I"]

我需要的是一个输出列表,它将以“I”开头的每个组分开:

output_list = [["I", "Non-I", "Non-I", "Non-I"], ["I", "Non-I", "Non-I", "Non-I"]]

我尝试了以下方法:

#!/usr/bin/env python3

from itertools import groupby

input_list = ["I", "Non-I", "Non-I", "Non-I", "I", "Non-I", "Non-I", "Non-I"]

output_list = [["I", "Non-I", "Non-I", "Non-I"], ["I", "Non-I", "Non-I", "Non-I"]]

for key, val in groupby(input_list, lambda x: x == "I"):
    print(list(val))

…它返回几乎我想要的:

['I']
['Non-I', 'Non-I', 'Non-I']
['I']
['Non-I', 'Non-I', 'Non-I']

现在我可以继续合并它,即合并所有其他元素,但这似乎是一个 hack。我还提出了“经典”的迭代方式:

ret = []
curr_list = []
for element in input_list:
    if element != "I":
        curr_list.append(element)
    if element == "I":
        if curr_list:
            ret.append(curr_list)
        curr_list = [element]
ret.append(curr_list)

有没有更 Pythonic 的方式来实现我的需要?

【问题讨论】:

  • “我”总是第一个列表项吗?如果没有,你能举一个期望的输入和输出的例子吗?
  • @Chris_Rands 是的,是的。良好的观察力。

标签: python itertools


【解决方案1】:

您可以将groupby 的输出设为生成器表达式,并通过将其与自身进行压缩来配对输出:

from itertools import groupby
groups = (list(g) for _, g in groupby(input_list, 'I'.__eq__))
print([[i for l in pair for i in l] for pair in zip(groups, groups)])

这个输出:

[['I', 'Non-I', 'Non-I', 'Non-I'], ['I', 'Non-I', 'Non-I', 'Non-I']]

【讨论】:

    【解决方案2】:

    一种方法是找到字符串以"I" 开头的索引,并使用itertools.islice 使用这些索引对列表进行切片:

    from itertools import islice
    
    ix = [ix for ix,i in enumerate(input_list) if i[0]=='I'] + [len(input_list)]
    input_ = iter(input_list)
    [list(islice(input_, i)) for i in ix[1:]]
    

    输出

    [['I', 'Non-I', 'Non-I', 'Non-I'], ['I', 'Non-I', 'Non-I', 'Non-I']]
    

    【讨论】:

      【解决方案3】:

      您可以使用索引来存储具有以下非 I 值的 I 的第一个实例:

      import itertools
      input_list = ["I", "Non-I", "Non-I", "Non-I", "I", "Non-I", "Non-I", "Non-I"]
      d = [list(b) for _, b in itertools.groupby(input_list, key=lambda x:x == 'I')]
      final_result = [[*d[i], *d[i+1]] for i in range(0, len(d), 2)]
      

      输出:

      [['I', 'Non-I', 'Non-I', 'Non-I'], ['I', 'Non-I', 'Non-I', 'Non-I']]
      

      【讨论】:

        【解决方案4】:

        同时寻找“I”:s 的索引,然后通过切片 input_list 为每个块创建一个单独的列表。

        location_list = [i for i, x in enumerate(input_list) if x == "I"]
        [input_list[i:j] for i,j in zip(location_list, location_list[1:]+[len(input_list)])]
        

        有输出:

        [['I', 'Non-I', 'Non-I', 'Non-I'], ['I', 'Non-I', 'Non-I', 'Non-I']]
        

        尝试不使用任何导入,以防您无法使用 itertools。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-05
          • 2021-01-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多