两个列表中无论元素排列顺序如何,如何在Python 2中找到它们的共同元素?

3

我希望找到一种方法,可以从两个不同的列表中找到所有相似的元素。

这两个列表如下所示:

A=[[[a1, b1],
  [a2, b2],
  [a3, b3]],
 [[a1, b2],
  [a2, b1],
  [a3, b3]],
 [[a1, b1],
  [a3, b2],
  [a2, b3]]]

B=[[[a1, b1],
  [a3, b3],
  [a2, b2]],
 [[a1, b2],
  [a2, b1],
  [a3, b3]],
 [[a1, b1],
  [a3, b2],
  [a2, b3]]]

我会将每个列表的第一个元素视为重复项: [[a1, b1], [a2, b2], [a3, b3]][[a1, b1], [a3, b3], [a2, b2]] 被视为重复项。

我要求的输出是,以单独的列表形式列出任一共同元素,如下所示:

C=[[a1, b1],[a2, b2], [a3, b3]]

我一直在处理这段代码,但它没有将前两个元素识别为重复项,我想知道应该添加什么来解决它。

C=[ i for i in A if i in B]

使用嵌套列表推导式和zip在一行中实现此操作:[[item_a for item_a in a_list if item_a in b_list] for a_list, b_list in zip(A, B)] - revliscano
3个回答

1
对于无序独特元素容器,请尝试使用Python集合!

https://docs.python.org/3.8/library/stdtypes.html#set

Python集合模型数学集合,它们是无序的唯一元素容器。从您的问题中并不完全清楚您认为什么是重复项。您可能需要创建集合的集合,但请注意,为了拥有包含集合的集合,您必须使用frozen_sets。 Python文档对此进行了很好的描述。
因此,您的新代码可能如下所示:
A = set([frozen_set((a1,b1),
(a2. b2),
(a3, b3))
frozen_set((a1, b2),
(a1, b1),
(a3, b3))
... # And so on

注意: 为了成为可哈希类型,内部列表被转换为元组

同样,集合和冻结集的确切实现取决于您认为顺序和唯一性很重要的元素是哪些。

集合交集

一旦您正确编写了集合数据结构,就可以使用集合交集找到所有共同的元素。

C = A & B

这相当于数学集合的交集。

TypeError: unhashable type: 'list' - r.ook
问题的类型是“列表”,而不是“元组”。如果需要将它们更改为“元组”以使您的答案有效,则对象转换应该是您答案的一部分。 - r.ook

1
A=[[["a1", "b1"],
  ["a2", "b2"],
  ["a3", "b3"]],
 [["a1", "b2"],
  ["a2", "b1"],
  ["a3", "b3"]],
 [["a1", "b1"],
  ["a3", "b2"],
  ["a2", "b3"]]]

B=[[["a1", "b1"],
  ["a3", "b3"],
  ["a2", "b2"]],
 [["a1", "b2"],
  ["a2", "b1"],
  ["a3", "b3"]],
 [["a1", "b1"],
  ["a3", "b2"],
  ["a2", "b4"]]]
ans=[]
for i in A:
    for j in B:
        for i1 in i:
            if i1 not in j:
                break
        else:
            ans.append(i)
            break
print ans

你可以尝试类似这样的东西。

这个完美运行!我能问一下代码的细节吗?因为我不是100%确定所有东西是如何工作的。所以我猜前几行是在比较A和B之间的元素,但i1是什么意思呢?它像i[1]吗? - Asiv
1
@Asiv 是的,i1i 的元素,即 ["a1", "b1"] - vks
好的,所以这段代码正在检查i1是否在B中的任何j元素中,如果是,则将i添加到ans列表中。我只是困惑于它如何识别元素为“重复项”,即使顺序不同。 - Asiv
1
如果i1不在j中,则i1为["a1", "b1"],而j为[["a1", "b1"], ["a3", "b3"], ["a2", "b2"]]。因此顺序无关紧要。 - vks
1
哦,我明白了。再次感谢您的帮助,非常完美!非常感谢。 - Asiv

1

为了比较无论顺序相同的子列表,一种方法是使用 zipmap 先对每个子列表进行排序:

l1 = [[['a1', 'b1'], ['a2', 'b2'], ['a3', 'b3']],
      [['a1', 'b2'], ['a2', 'b1'], ['a3', 'b3']],
      [['a1', 'b1'], ['a3', 'b2'], ['a2', 'b3']]]
l2 = [[['a1', 'b1'], ['a3', 'b3'], ['a2', 'b2']],
      [['a1', 'b2'], ['a2', 'b1'], ['a3', 'b3']],
      [['a1', 'b1'], ['a3', 'b2'], ['a2', 'b4']]]

                              # sort the sublists first          # check if the sorted lists are equal        
result = [x for x, y in zip(*(map(sorted, l) for l in (l1, l2))) if x == y]

相同子列表 结果:

[[['a1', 'b1'], ['a2', 'b2'], ['a3', 'b3']],
 [['a1', 'b2'], ['a2', 'b1'], ['a3', 'b3']]]

更新:由于您正在使用sympy并遇到错误,很可能是在sorted函数上发生的,按照这个问题尝试此解决方案。请改用此解决方案。
                                       # check if all items in x are also part of y
result = [x for x, y in zip(l1, l2) if all(subx in y for subx in x)]

如果您只关心获取每个子列表中的共同元素,这里有另一种方法:
          # check for common elements, put them in a list and return
result = [[sub_x for sub_x in x if sub_x in y] for x, y in zip(l1, l2)]

常见元素 结果:
[[['a1', 'b1'], ['a2', 'b2'], ['a3', 'b3']],
 [['a1', 'b2'], ['a2', 'b1'], ['a3', 'b3']],
 [['a1', 'b1'], ['a3', 'b2']]]

嘿,这也很好啊!我试图在另外两个列表上使用它,但是却出现了一个错误“无法确定关系的真值”。我想这可能与我在sympy中将a1、a2、b1等定义为符号而不是字符串有关。那么这样做会影响您在此处提供的代码吗? - Asiv
1
我不是 sympy 的用户,但有没有一种方法可以测试对象的相等性?如果有的话,我会用那个测试来替换 x == y 部分,例如 if all(sympy.eq(x1, y1) for x1, y1 in zip(x, y)) - r.ook
谢谢您的输入!我会尝试看看是否有任何解决办法。 - Asiv
1
看起来问题出在 sorted 函数上:https://dev59.com/8Q76s4cB2Jgan1znM2fT。如果是这种情况,需要采用不同的方法。我已经更新了答案,请看是否有帮助。 - r.ook
1
你真的非常有帮助,非常感谢。代码完美运行! - Asiv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接