Python:如果元素是另一个嵌套列表中的元素,则在嵌套列表中删除重复的元素

时间:2019-08-07 17:00:06

标签: python list nested-lists drop-duplicates

如何基于另一个嵌套列表中的元素对嵌套列表中的元素进行重复数据删除? 或者,遍历一列并根据另一列中的元素列表删除重复项是否更有意义?

Column 1
R1 = [foo, bar, baz, qux,] 
R2 = [Cat, Dog, Frog, Bird]
R3 = [Salad, Potato, Pizza, Soda

Column 2
R1 = [bar, quuz, quux, qux]
R2 = [Fish, Dog, Cow]
R3 = [Potato, Milk, Apple, Pizza]

我只关心保持listB唯一的元素,顺序无关紧要

Final Column
R1 = [quuz, quux]
R2 = [Fish, Cow]
R3 = [Milk, Apple]

实际列表如下所示,并包含以下字符:\,()

[Youth Counselor / Worker, Nutrition / Dietetic Technician,Mathematician,Tailor / Seamstress,Librarian]

我必须将每个元素都保护为字符串,以便在这种情况下无法使用平面列表

4 个答案:

答案 0 :(得分:3)

如果顺序无关紧要:

  • 在每对嵌套列表上使用set operations。将两个集合相减会产生一个新集合,其中仅包含第一个中的元素而第二个中不出现。
  • 使用zip() function将两个输入列表中的嵌套列表配对。
  • 如果您的输出必须再次包含嵌套列表,请使用list()
  • 将set操作的结果转换回列表。
  • 使用列表推导来处理每对嵌套列表,并使用结果创建一个新列表。

这可以表示为单线:

[list(set(b) - set(a)) for a, b in zip(listA, listB)]

如果输出中的嵌套集可以接受,则可以放弃list(...)调用:

[set(b) - set(a) for a, b in zip(listA, listB)]

演示:

>>> listA = [['A', 'B', 'C', 'D', 'E'], [1, 2, 3, 4, 5], ['!', '@', '#', '$', '%']]
>>> listB = [['E', 'A', 'T', 'F', 'W'], [5, 6, 8, 2, 9], ['@', '^', '&', '#', '*']]
>>> [list(set(b) - set(a)) for a, b in zip(listA, listB)]
[['W', 'F', 'T'], [8, 9, 6], ['^', '&', '*']]
>>> [set(b) - set(a) for a, b in zip(listA, listB)]  # without list(...)
[{'W', 'F', 'T'}, {8, 9, 6}, {'^', '&', '*'}]

如果您改变主意并确定顺序对输出至关重要,那么:

  • 仅将listA中的每个嵌套列表转换为一次一次,以进行更快的遏制测试。 value in listobject每次都必须迭代listobject,而value in setobject使用散列来测试在O(1)(恒定)时间内是否包含。
  • 遍历listB中给定嵌套列表中的值,并针对listA中的匹配集测试该值,仅保留未出现在相应集中的值。为此,请使用列表理解。
  • 在配对列表时,可以使用map()来处理listA嵌套列表到集合的转换。这样有助于避免每次您测试listB的嵌套列表中的值时都创建新集。

因此,可以保留输入顺序的单行代码是:

[[v for v in nested_b if v not in set_a] for set_a, nested_b in zip(map(set, listA), listB)]

zip()函数将listA(通过map(set, listA))产生的集合与listB的嵌套列表配对,因此我们可以在最外层的每次迭代中将它们一起使用列表理解。然后,嵌套列表推导会过滤每个嵌套列表的值:

>>> [[v for v in nested_b if v not in set_a] for set_a, nested_b in zip(map(set, listA), listB)]
[['T', 'F', 'W'], [6, 8, 9], ['^', '&', '*']]

答案 1 :(得分:0)

使用sets,您可以执行以下操作:

listA = [["A","B","C","D","E"],[1,2,3,4,5],["!","@","#","$","%"]]
listB = [["E","A","T","F","W"],[5,6,8,2,9],["@","^","&","#","*"]]


print([list(set(listB[i]).difference(set(listA[i]))) for i in range(len(listB))])

给我:

[['F', 'W', 'T'], [8, 9, 6], ['^', '&', '*']]

注意:它将更改列表的顺序。

  

编辑:

     

或者按照@ user3483203的建议,比这更可靠的解决方案是:

[[list(b - a) for a, b in zip(map(set, listA), map(set, listB))]

答案 2 :(得分:0)

假设您要按列表索引进行检查

result_list = []
for listA_nest,listB_nest zip(listA,listB):
    result_list.append(list(filter(lambda listB_el: listB_el not in listA_nest ,listB_nest))

类似的东西应该起作用,可能有更好的解决方案。

单行解决方案:

result_list = [list(filter(lambda listB_el: listB_el not in set(listA_nest) ,listB_nest)) for listA_nest,listB_nest in zip(listA,listB)]

答案 3 :(得分:0)

假设您正在检查A和B中的相应列表,则可能希望zip将它们保持在一起,并且可以使用in方法来检查成员资格:

listFinal = []
for l1, l2 in zip(listA, listB):
    l = [x for x in l2 if x not in l1]
    listFinal.append(l)

[['T', 'F', 'W'], [6, 8, 9], ['^', '&', '*']]

虽然更快的方法是使用set,它使您可以快速删除重复的集合并测试O(1)而不是O(N)的成员资格。

listFinal = []

for l1, l2 in zip(listA, listB):
    # set subtraction here will remove all elements present in l1 from l2
    l = set(l2) - set(l1)
    listFinal.append(list(l))

[['T', 'F', 'W'], [8, 9, 6], ['*', '&', '^']]

或者,如果愿意,可以一行

listFinal = [list(set(l2) - set(l1)) for l1, l2 in zip(listA, listB)]

显示zip的工作方式:

a = [1, 2, 3, 4]
b = [5, 6, 7, 8]

for x, y in zip(a, b):
    print(x, y)

1 5
2 6
3 7
4 8

它将为传递给它的每个可迭代对象生成相应的元素组。

设置减法:

a = set('a', 'b', 'c')
b = set('b', 'c', 'd')

a - b

{'a'}