在Python中查找两个字符串列表的交集

8

我已经查阅了三篇文章,链接如下:Find intersection of two lists?, Intersection of Two Lists Of Strings, Getting intersection of two lists in python。但是,使用Python找到两个字符串列表之间的交集仍然困难。

我有两个变量。

A = [['11@N3'], ['23@N0'], ['62@N0'], ['99@N0'], ['47@N7']]

B  = [['23@N0'], ['12@N1']]

如何找到“23@N0”是A和B的一部分?
我尝试使用在http://www.saltycrane.com/blog/2008/01/how-to-find-intersection-and-union-of/中提到的intersect(a,b)。但是,当我尝试将A转换为set时,它会抛出一个错误:
File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list'

为了将其转换为集合,我使用了TypeError: unhashable type: 'list' when using built-in set function中的方法,可以使用以下方式将列表转换:
result = sorted(set(map(tuple, A)), reverse=True)

将其转换为元组,然后可以将元组转换为集合。但是这会返回一个空集作为交集。
您能帮助我找到交集吗?

1
最快的交集大量数据的方法是使用Python集合。Python集合是哈希映射,因此需要哈希。你的问题来自于将字符串包装成列表。列表是可变对象,这就是为什么它们不能被哈希,而字符串是不可变的,所以可以被哈希。 - Eli Korvigo
1
你为什么在每个列表中只有一个字符串? - Peter Wood
这是我拥有的数据集,我没有生成它,是从别人那里借来的。 - Sharath Chandra
@SharathChandra: "borrowed" 是什么意思?你是从文件中读取的吗?文件格式是什么? - jfs
@J.F.Sebastian:是的,我已经从文件中读取了它。它是json格式的。 - Sharath Chandra
7个回答

7
你可以使用compiler.ast模块的flatten函数来展开你的子列表,然后像这样应用集合交集。
from compiler.ast import flatten

A=[['11@N3'], ['23@N0'], ['62@N0'], ['99@N0'], ['47@N7']]
B=[['23@N0'], ['12@N1']]

a = flatten(A)
b = flatten(B)
common_elements = list(set(a).intersection(set(b)))
common_elements
['23@N0']

4
compiler.ast 只适用于 Python 2;建议使用 itertools.chain。 - Antti Haapala -- Слава Україні
我同意你的观点,但如果输入列表像这样 A= ['11@N3', ['23@N0']],那么应用itertools.chain将不能真正地展平列表。在list(itertools.chain(*A))之后得到的列表将是['1', '1', '@', 'N', '3', '23@N0']。 - Anurag Sharma
真的,我们需要一个可以理解字符串和字节的“flatten”迭代工具。 - Antti Haapala -- Слава Україні
@AnttiHaapala:也许你正在寻找如何在Python中展开(不规则)列表的列表 - jfs
这个问题不需要任何一个,除了那里的许多答案在3中都行不通。我的意思是,它应该在核心中用C语言编写。 - Antti Haapala -- Слава Україні

2

如果你需要将其放在幸运饼干上:

set(i[0] for i in A).intersection(set(i[0] for i in B))

2
问题在于你的列表包含子列表,因此无法转换为集合。请尝试以下方法:
A=[['11@N3'], ['23@N0'], ['62@N0'], ['99@N0'], ['47@N7']]
B=[['23@N0'], ['12@N1']]

C = [item for sublist in A for item in sublist]
D = [item for sublist in B for item in sublist]

print set(C).intersection(set(D))

2
您的数据结构有些奇怪,因为它是一个由字符串的一元素列表组成的列表;您需要将其缩减为一个字符串列表,然后就可以应用之前的解决方案:
因此,像这样的列表:
B = [['23@N0'], ['12@N1']]

可以通过转换为迭代器,以便迭代'23@N0','12@N1'

使用itertools.chain(*),因此我们有一个简单的一行代码:

>>> set(chain(*A)).intersection(chain(*B))
{'23@N0'}

如果在最后一个语句中A和B被颠倒,这似乎是有效的。也就是说,如果我们尝试set(B).intersection(A),它会得到一个空集合。 - Sharath Chandra

0

我的偏好是使用标准库中的 itertools.chain

from itertools import chain

A = [['11@N3'], ['23@N0'], ['62@N0'], ['99@N0'], ['47@N7']]

B = [['23@N0'], ['12@N1']]

set(chain(*A)) & set(chain(*B))

# {'23@N0'}

0
你有两个包含一个元素的列表的列表。为了将其转换为集合,你必须将其变为一个字符串列表:
set_a = set([i[0] for i in A])
set_b = set([i[0] for i in B])

现在你可以获得交集:

set_a.intersection(set_b)

你不需要在括号内加上[]set(x[0] for x in A) & set(x[0] for x in B) - jfs

0
A=[['11@N3'], ['23@N0'], ['62@N0'], ['99@N0'], ['47@N7']]
A=[a[0] for a in A]
B=[['23@N0'], ['12@N1']]
B=[b[0] for b in B]
print set.intersection(set(A),set(B))

输出:set(['23@N0'])

如果您的列表中每个子列表仅有1个元素,则可以尝试此方法。


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