删除包含反向的子列表重复项

问题描述 投票:2回答:7

例如,我有以下内容

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)

但是最后我得到的名单与原始名单相同。我不确定我的匹配条件是否正确。

任何帮助都会有用。谢谢!

python nested-lists
7个回答
3
投票

您可以遍历列表的元素,并使用set跟踪到目前为止已看到的元素。使用集合是检查成员资格的一种更方便的方法,因为操作的复杂度较低,在这种情况下,由于列表不可散列,因此您需要使用元组。然后,如果没有看到实际的元组或reversed,则保留这些项目(如果您只想忽略那些具有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
投票
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'处的元素是否等于其反向元素,这种情况永远不会发生!因此得到相同的结果


2
投票

Approach1:

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)

Approach2:

您也可以这样尝试:

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

1
投票
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
投票

这类似于@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']]

因为请求宽恕比许可容易

注意:在循环时删除元素不是一件好事,但是对于此特定问题,这没有害处。实际上,这样做是更好的,因为我们不必再次检查镜像。我们已经将其删除。


0
投票

正如我在评论中所写,切勿使用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 = [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 module

functools

逻辑与第一版的逻辑相同。


0
投票

您也可以尝试以下操作:-

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

输出:-

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)
© www.soinside.com 2019 - 2024. All rights reserved.