Как удалить одинаковый элемент для нескольких списков python?

Есть несколько списков в Python, пример:

list_1 = ['a', 'None', 'b', 'None', 'None', 'c', 'None', 'd']
list_2 = ['a', 'None', 'b', 'c', 'None', 'd', 'None',]
list_3 = ['a', 'None', 'b', 'None', 'None', 'c', 'None', 'd', 'e', 'f']

Не обязательно, чтобы размер у этих списков был одинаковый. Подскажите, пожалуйста, как удалить из нескольких списков значение "None" (да, в нашем списке None это строка) на одинаковых индексах?

Например, в итоге должен остаться лишь такие значения в списках:

list_1 = ['a', 'b', 'None', 'c', 'd']
list_2 = ['a', 'b', 'c', 'd']
list_3 = ['a', 'b', 'None', 'c', 'd', 'e', 'f']

В коде эти списки хранятся в словаре. Пример:

some_dict = {
    'key1' = list_1,
    'key2' = list_2,
    'key3' = list_3,
}

Пока что не могу сообразить в алгоритм, который тут проще и легче всего применить. Огромная просьба учитывать наличие самого словаря. Буду очень признателен за подсказку!


Ответы (4 шт):

Автор решения: denisnumb

Как вариант — можно пробежаться циклом for сразу по всем трем спискам.

Для этого воспользуемся функцией zip(), а также создадим переменную индекса, с которым в данный момент работаем:

for index, (a, b, c) in enumerate(zip(*some_dict.values())):
   . . .

Далее, внутри цикла проверим условие, то что текущий элемент 1, 2 и 3 списка равен 'None' и, если это так, то удалим текущий индекс из всех трех списков (при условии, что индекс не выходит за границы списка):

for index, (a, b, c) in enumerate(zip(*some_dict.values())):
    if a == b == c == 'None':
        for list_ in (list_1, list_2, list_3):
            if index < len(list_):
                del list_[index]

Если вывести все три списка после этих манипуляций, то на выходе получим результат:

['a', 'b', 'None', 'c', 'd']
['a', 'b', 'c', 'd']
['a', 'b', 'None', 'c', 'd', 'e', 'f']

Полный код:

some_dict = {
    'key1': ['a', 'None', 'b', 'None', 'None', 'c', 'None', 'd'],
    'key2': ['a', 'None', 'b', 'c', 'None', 'd', 'None',],
    'key3': ['a', 'None', 'b', 'None', 'None', 'c', 'None', 'd', 'e', 'f'],
}

for index, (a, b, c) in enumerate(zip(*some_dict.values())):
    if a == b == c == 'None':
        for list_ in some_dict.values():
            if index < len(list_):
                del list_[index]

print(*some_dict.values(), sep='\n')
→ Ссылка
Автор решения: splash58

Для расширения ассортимента

В коде сделано допущение, что все элементы не приводятся к False

from  itertools import zip_longest

result = {}

for v in zip_longest(*some_dict.values(), fillvalue=False):
    if not all(map(lambda x: x == 'None', v)):
        for k, y in zip(some_dict.keys(), v):
            if y:
                result.setdefault(k, []).append(y)

print(*result.values(), sep='\n')
→ Ссылка
Автор решения: SergFSM

еще вариант для ассортимента:

from itertools import compress, zip_longest


filt = [not a==b==c=='None' for a,b,c in zip_longest(*some_dict.values())]
some_dict = {k:list(compress(v, filt)) for k,v in some_dict.items()}

>>> some_dict
'''
{'key1': ['a', 'b', 'None', 'c', 'd'],
 'key2': ['a', 'b', 'c', 'd'],
 'key3': ['a', 'b', 'None', 'c', 'd', 'e', 'f']}
→ Ссылка
Автор решения: Stanislav Volodarskiy

Ещё один вариант с zip_longest. В качестве fillvalue используется уникальный объект, что гарантирует корректную работу с любыми данными.

import itertools


def clean(lists):
    keys, sources = zip(*lists.items())
    targets = [[] for _ in sources]
    blank = object()
    for v in itertools.zip_longest(*sources, fillvalue=blank):
        if any(map(lambda x: x != 'None', v)):
            for i, t in zip(v, targets):
                if i is not blank:
                    t.append(i)
    return dict(zip(keys, targets))


lists = {
    'key1': ['a', 'None', 'b', 'None', 'None', 'c', 'None', 'd'],
    'key2': ['a', 'None', 'b', 'c', 'None', 'd', 'None'],
    'key3': ['a', 'None', 'b', 'None', 'None', 'c', 'None', 'd', 'e', 'f']
}
result = clean(lists)
{'key1': ['a', 'b', 'None', 'c', 'd'],
 'key2': ['a', 'b', 'c', 'd'],
 'key3': ['a', 'b', 'None', 'c', 'd', 'e', 'f']}
→ Ссылка