删除子列表重复的内容,包括反向的

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

例如,我有以下内容

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

我想匹配一个子列表中是否有一个反转的子列表(即['1', '2'] = ['2', '1']),如果为真,则从列表中删除镜像的那个。

最后的列表应该是这样的。

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
5个回答
3
投票

你可以对列表中的元素进行迭代,并使用一个叫做 "反转子列表 "的函数来匹配。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
投票
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
投票

办法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)

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 模块:

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

逻辑和第一个版本的逻辑是一样的。


0
投票

你也可以试试这个:-

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