Разделение списка на основе изменения значения с помощью itertools - PullRequest
3 голосов
/ 18 апреля 2019

У меня есть список, который я пытаюсь сгруппировать по изменению значения:

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)

Есть ли более Pythonic способ достижения того, что мне нужно?

Ответы [ 4 ]

1 голос
/ 18 апреля 2019

Также ищем индексы "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.

1 голос
/ 18 апреля 2019

Один из способов - найти индексы, в которых строка начинается с "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']]
1 голос
/ 18 апреля 2019

Вы можете сделать вывод 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']]
1 голос
/ 18 апреля 2019

Вы можете использовать индексы для хранения первого экземпляра 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']]
...