使用itertools根据值的变化拆分列表

时间:2019-04-18 15:07:27

标签: python itertools

我有一个要按值变化分组的列表:

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']

现在我可以继续进行合并,即合并所有其他元素,但这似乎很简单。我还提出了“经典”的迭代方式:

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)

是否有更Python化的方式来实现我所需要的?

4 个答案:

答案 0 :(得分:1)

您可以使用索引存储具有以下非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']]

答案 1 :(得分:1)

一种方法是找到以"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']]

答案 2 :(得分: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']]

答案 3 :(得分:1)

还要查找“ 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,请尝试不使用任何导入。