Удалить дубликаты подсписок, в том числе перевернутые - PullRequest
2 голосов
/ 06 мая 2020

Например, у меня есть следующие

list = [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '1'], ['4', '1'], ['2', '6']]

Я хочу сопоставить, если подсписок имеет перевернутый подсписок в том же списке (например, ['1', '2'] = ['2', '1']), и если True, чем удалить из списка зеркальный.

Окончательный список должен выглядеть так:

list = [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5']['2', '6']]

Вот что я пробовал:

for i in range(len(list)):
    if list[i] == list[i][::-1]:
            print("Match found")
            del list[i][::-1]

print(list)

Но в итоге я получаю тот же список, что и оригинал. Я не уверен, правильно ли мое условие соответствия.

Ответы [ 7 ]

3 голосов
/ 06 мая 2020

Вы можете перебирать элементы списка и использовать set, чтобы отслеживать те, которые были замечены до сих пор. Использование набора - более удобный способ проверки членства, поскольку операция имеет меньшую сложность , и в этом случае вам нужно будет работать с кортежами, поскольку списки не хэшируемые. Затем просто сохраните эти элементы, если ни фактический кортеж, ни reversed не были замечены (если вы просто хотите игнорировать те, которые имеют перевернутый , вам просто нужно if tuple(reversed(t)) in s):

s = set()
out = []
for i in l:
    t = tuple(i)
    if t in s or tuple(reversed(t)) in s:
        continue
    s.add(t)
    out.append(i)
print(out)
# [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '6']]
2 голосов
/ 06 мая 2020

Подход1:

new_list = []
for l in List:
    if l not in new_list and sorted(l) not in new_list:
        new_list.append(l)

print(new_list)

Подход2:

Вы также можете попробовать следующее:

seen = set()
print([x for x in List if frozenset(x) not in seen and not seen.add(frozenset(x))])

[['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '6']]
2 голосов
/ 06 мая 2020
lists = [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '1'], ['4', '1'], ['2', '6']]
for x in lists:
    z=x[::-1]
    if z in lists:
        lists.remove(z)

Объяснение: Перебирая списки, переверните каждый элемент и сохраните в 'z'. Теперь, если 'z' существует в списках, удалите его с помощью remove ()

Проблема с вашим решением заключается в том, что вы проверяете при использовании индекса 'i', что означает, равен ли элемент в 'i' его обратное, чего никогда не может быть !! следовательно, получение тех же результатов

1 голос
/ 06 мая 2020
my_list = [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '1'], ['4', '1'], ['2', '6']]
my_list = list(set([sorted(l) for l in my_list]))
0 голосов
/ 06 мая 2020

Вы также можете попробовать это: -

l = [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '1'], ['4', '1'], ['2', '6']]
res = []

for sub_list in l:
    if sub_list[::-1] not in res:
        res.append(sub_list)

print(res)

Вывод: -

[['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '6']]
0 голосов
/ 06 мая 2020

Как я написал в комментарии, никогда не используйте list (или любые встроенные) в качестве имени переменной:

L = [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '1'], ['4', '1'], ['2', '6']]

Посмотрите свой код:

for i in range(len(L)):
    if L[i] == L[i][::-1]:
        print("Match found")
        del L[i][::-1]

Есть две проблемы. Сначала вы сравниваете L[i] с L[i][::-1], но вы хотите сравнить L[i] с L[j][::-1] для любого j != i. Во-вторых, вы пытаетесь удалить элементы списка во время итерации. Если вы удаляете элемент, длина списка уменьшается, и индекс l oop будет за пределами списка:

>>> L = [1,2,3]
>>> for i in range(len(L)):
...     del L[i]
... 
Traceback (most recent call last):
...
IndexError: list assignment index out of range

Чтобы исправить первую проблему, вы можете повторить итерацию дважды элементы: существует ли для каждого элемента другой элемент, противоположный первому? Чтобы исправить вторую проблему, у вас есть два варианта: 1. создать новый список; 2. действуйте в обратном порядке, чтобы удалить первые последние индексы.

Первая версия:

new_L = []
for i in range(len(L)):
    for j in range(i+1, len(L)):
        if L[i] == L[j][::-1]:
            print("Match found")
            break
    else: # no break
        new_L.append(L[i])

print(new_L)    

Вторая версия:

for i in range(len(L)-1, -1, -1):
    for j in range(0, i):
        if L[i] == L[j][::-1]:
            print("Match found")
            del L[i]

print(L)    

(Для лучшей временной сложности , см. ответ @ yatu.)


Для однострочника вы можете использовать модуль functools :

>>> L = [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '1'], ['4', '1'], ['2', '6']]
>>> import functools
>>> functools.reduce(lambda acc, x: acc if x[::-1] in acc else acc + [x], L, [])
[['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '6']]

logi c то же, что и лог c первой версии.

0 голосов
/ 06 мая 2020

Это похоже на решение @Mehul Gupta, но я думаю, что их решение дважды просматривает список при совпадении: один для проверки и один для удаления. Вместо этого мы могли бы

the_list = [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '1'], ['4', '1'], ['2', '6']]
for sub_list in the_list:
    try:
        idx = the_list.index(sub_list[::-1])
    except ValueError:
        continue
    else:
        the_list.pop(idx)

print(the_list)
# [['1', '2'], ['1', '3'], ['1', '4'], ['1', '5'], ['2', '6']]

, потому что проще просить прощения, чем разрешение .

Примечание: удаление элементов во время цикла не очень хорошо, но для этого конкретная c проблема, не вредит. Фактически, это лучше, потому что мы больше не проверяем зеркальное отображение; мы уже удалили его.

...