在元组列表上设置理论魔法
Set theory magic on list of tuples
在 python 中,我有两个列表 A
和 B
。两个列表都由元组 (x,y)
组成。例如:
A = [('x1','y1'), ('x2','y2'), ('x3','y3')]
B = [('x1','y1'), ('x2','y5'), ('x4','y4')]
现在,我想要三个结果。如果不涉及元组,所有这些都可以用集合论轻松解决。
结果 1:两个列表的交集:set(A) & set(B)
)。所以结果应该是比较两个列表的元组的两个值。结果应该是:C = [('x1','y1')]
结果 2:两个列表的交集,其中只有 (x,y)[0]
匹配。结果应为:D = (('x1','y1'), ('x2', ('y2', 'y5'))]
。理想的解决方案是 D - C -> E = [('x2', ('y2', 'y5'))]
但我可以接受 D
本身。
结果 3:列表 B
与 A
相比的唯一性:set(B)-(set(A) & set(B))
。仅在 (x,y)[0]
上进行了比较。结果应为:[('x4', 'y4')]
.
我找不到关于这些问题的任何信息,也无法自己构建解决方案。有人可以帮忙吗?
为什么不使用 python 的 set()
? 1 非常直接,2 只是需要多做一点工作:
A = [('x1','y1'), ('x2','y2'), ('x3','y3')]
B = [('x1','y1'), ('x2','y5'), ('x4','y4')]
a,b = set(A),set(B)
print '1:',a&b
axs = set(map(itemgetter(0),A))
bxs = set(map(itemgetter(0),B))
result2 = []
for c in axs&bxs:
result2.append((c,set([y for x,y in A+B if x==c]))
print '2:',result2
输出:
1: set([('x1', 'y1')])
2: [('x2', set(['y2', 'y5'])), ('x1', set(['y1']))]
你可以对 3 使用非常相似的方法
这里有一些方法可以使用听写来做你想做的事情。这是Python2代码;它需要对 Python 3 进行一些小的修改。IIRC,Python 3 没有 dict.iteritems()
,因为它的 dict.items()
returns 是迭代器而不是列表。
A = [('x1','y1'), ('x2','y2'), ('x3','y3')]
B = [('x1','y1'), ('x2','y5'), ('x4','y4')]
dA = dict(A)
dB = dict(B)
#Intersection, the simple way
print 'Result 1a:', list(set(A) & set(B))
#Intersection using dicts instead of sets
result = [(k, vA) for k, vA in dA.iteritems() if dB.get(k) == vA]
print 'Result 1b:', result
#match on 1st tuple element, ignoring 2nd element
result = {}
for k, vA in dA.iteritems():
vB = dB.get(k)
if vB:
result[k] = (vA, vB) if vB != vA else vA
print 'Result 2a:', result.items()
#match on 1st tuple element only if 2nd elements don't match
result = {}
for k, vA in dA.iteritems():
vB = dB.get(k)
if vB and vB != vA:
result[k] = (vA, vB)
print 'Result 2b:', result.items()
#unique elements of B, ignoring 2nd element
result = [(k, vB) for k, vB in dB.iteritems() if k not in dA]
print 'Result 3:', result
输出
Result 1a: [('x1', 'y1')]
Result 1b: [('x1', 'y1')]
Result 2a: [('x2', ('y2', 'y5')), ('x1', 'y1')]
Result 2b: [('x2', ('y2', 'y5'))]
Result 3: [('x4', 'y4')]
两个列表的交集:
您已经知道解决方案:set(A) & set(B)
。或者,等价地,set(A).intersection(B)
.
>>> A = [('x1', 'y1'), ('x2', 'y2'), ('x3', 'y3')]
>>> B = [('x1', 'y1'), ('x2', 'y5'), ('x4', 'y4')]
>>> set(A).intersection(B)
{('x1', 'y1')}
只有 (x,y)[0] 匹配的两个列表的交集:
首先,确保 A
和 B
都按它们的 x 坐标排序。
然后使用itertools.groupby()和字典:
>>> a_grouped = {x: list(points) for x, points in
... itertools.groupby(A, lambda point: point[0])}
>>> b_grouped = {x: list(points) for x, points in
... itertools.groupby(B, lambda point: point[0])}
>>> [(x, {point[1] for point in a_grouped[x] + b_grouped[x]})
... for x in a_grouped if x in b_grouped]
[('x2', {'y5', 'y2'}), ('x1', {'y1'})]
(这和你问的不太一样,因为正如你所见,我们有 ('x1', {'y1'})
而不是 ('x1', 'y1')
。此外,我们有集合而不是列表,但是这些这两件事都很容易解决。)
如果要排除共同点:在调用 groupby() 之前从 A
和 B
中删除它们:
>>> A = set(A)
>>> B = set(B)
>>> common_points = A & B
>>> A = [point for point in A if point not in common_points]
>>> B = [point for point in B if point not in common_points]
列表 B
与 A
相比的唯一性,仅在 (x,y)[0]
上进行比较:
构造A
中点的所有x坐标的集合:
>>> exclude = {point[0] for point in A}
>>> [point for point in B if point[0] not in exclude]
[('x4', 'y4')]
注意 exclude
的元素是 a_grouped
的键——这意味着您可以重用上一题的部分代码并写成:
>>> [point for point in B if point[0] not in a_grouped]
[('x4', 'y4')]
对于所有这些解决方案,性能和可读性都可以提高,如果您要使用我的代码,请考虑这一点。
在 python 中,我有两个列表 A
和 B
。两个列表都由元组 (x,y)
组成。例如:
A = [('x1','y1'), ('x2','y2'), ('x3','y3')]
B = [('x1','y1'), ('x2','y5'), ('x4','y4')]
现在,我想要三个结果。如果不涉及元组,所有这些都可以用集合论轻松解决。
结果 1:两个列表的交集:set(A) & set(B)
)。所以结果应该是比较两个列表的元组的两个值。结果应该是:C = [('x1','y1')]
结果 2:两个列表的交集,其中只有 (x,y)[0]
匹配。结果应为:D = (('x1','y1'), ('x2', ('y2', 'y5'))]
。理想的解决方案是 D - C -> E = [('x2', ('y2', 'y5'))]
但我可以接受 D
本身。
结果 3:列表 B
与 A
相比的唯一性:set(B)-(set(A) & set(B))
。仅在 (x,y)[0]
上进行了比较。结果应为:[('x4', 'y4')]
.
我找不到关于这些问题的任何信息,也无法自己构建解决方案。有人可以帮忙吗?
为什么不使用 python 的 set()
? 1 非常直接,2 只是需要多做一点工作:
A = [('x1','y1'), ('x2','y2'), ('x3','y3')]
B = [('x1','y1'), ('x2','y5'), ('x4','y4')]
a,b = set(A),set(B)
print '1:',a&b
axs = set(map(itemgetter(0),A))
bxs = set(map(itemgetter(0),B))
result2 = []
for c in axs&bxs:
result2.append((c,set([y for x,y in A+B if x==c]))
print '2:',result2
输出:
1: set([('x1', 'y1')])
2: [('x2', set(['y2', 'y5'])), ('x1', set(['y1']))]
你可以对 3 使用非常相似的方法
这里有一些方法可以使用听写来做你想做的事情。这是Python2代码;它需要对 Python 3 进行一些小的修改。IIRC,Python 3 没有 dict.iteritems()
,因为它的 dict.items()
returns 是迭代器而不是列表。
A = [('x1','y1'), ('x2','y2'), ('x3','y3')]
B = [('x1','y1'), ('x2','y5'), ('x4','y4')]
dA = dict(A)
dB = dict(B)
#Intersection, the simple way
print 'Result 1a:', list(set(A) & set(B))
#Intersection using dicts instead of sets
result = [(k, vA) for k, vA in dA.iteritems() if dB.get(k) == vA]
print 'Result 1b:', result
#match on 1st tuple element, ignoring 2nd element
result = {}
for k, vA in dA.iteritems():
vB = dB.get(k)
if vB:
result[k] = (vA, vB) if vB != vA else vA
print 'Result 2a:', result.items()
#match on 1st tuple element only if 2nd elements don't match
result = {}
for k, vA in dA.iteritems():
vB = dB.get(k)
if vB and vB != vA:
result[k] = (vA, vB)
print 'Result 2b:', result.items()
#unique elements of B, ignoring 2nd element
result = [(k, vB) for k, vB in dB.iteritems() if k not in dA]
print 'Result 3:', result
输出
Result 1a: [('x1', 'y1')]
Result 1b: [('x1', 'y1')]
Result 2a: [('x2', ('y2', 'y5')), ('x1', 'y1')]
Result 2b: [('x2', ('y2', 'y5'))]
Result 3: [('x4', 'y4')]
两个列表的交集:
您已经知道解决方案:
set(A) & set(B)
。或者,等价地,set(A).intersection(B)
.>>> A = [('x1', 'y1'), ('x2', 'y2'), ('x3', 'y3')] >>> B = [('x1', 'y1'), ('x2', 'y5'), ('x4', 'y4')] >>> set(A).intersection(B) {('x1', 'y1')}
只有 (x,y)[0] 匹配的两个列表的交集:
首先,确保
A
和B
都按它们的 x 坐标排序。然后使用itertools.groupby()和字典:
>>> a_grouped = {x: list(points) for x, points in ... itertools.groupby(A, lambda point: point[0])} >>> b_grouped = {x: list(points) for x, points in ... itertools.groupby(B, lambda point: point[0])} >>> [(x, {point[1] for point in a_grouped[x] + b_grouped[x]}) ... for x in a_grouped if x in b_grouped] [('x2', {'y5', 'y2'}), ('x1', {'y1'})]
(这和你问的不太一样,因为正如你所见,我们有
('x1', {'y1'})
而不是('x1', 'y1')
。此外,我们有集合而不是列表,但是这些这两件事都很容易解决。)如果要排除共同点:在调用 groupby() 之前从
A
和B
中删除它们:>>> A = set(A) >>> B = set(B) >>> common_points = A & B >>> A = [point for point in A if point not in common_points] >>> B = [point for point in B if point not in common_points]
列表
B
与A
相比的唯一性,仅在(x,y)[0]
上进行比较:构造
A
中点的所有x坐标的集合:>>> exclude = {point[0] for point in A} >>> [point for point in B if point[0] not in exclude] [('x4', 'y4')]
注意
exclude
的元素是a_grouped
的键——这意味着您可以重用上一题的部分代码并写成:>>> [point for point in B if point[0] not in a_grouped] [('x4', 'y4')]
对于所有这些解决方案,性能和可读性都可以提高,如果您要使用我的代码,请考虑这一点。