Python获取两个元组列表的并集,基于元组的三个元素中的两个
我的程序运行得不太好。在一个循环中,每个处理器的数据(一个元组的列表)都被收集到主处理器里,然后需要清理这些数据,去掉相似的元素。
我在网上,特别是在这个网站上,找到了很多有趣的线索,关于如何合并列表的。不过,我还没能把这些方法应用到我的问题上。我的目标是去掉那些最后两个元素和列表中其他元组相似的元组。例如:
list1=[[a,b,c],[d,e,f],[g,h,i]]
list2=[[b,b,c],[d,e,a],[k,h,i]]
the result should be:
final=[[a,b,c],[d,e,f],[g,h,i],[d,e,a]]
现在我在用循环和中断,但我希望能让这个过程更快。
这是我的代码样子(result和temp是我想要合并的列表),我用的是python2.6。
for k in xrange(len(temp)):
u=0
#index= next((j for j in xrange(lenres) if temp[k][1:3] == result[j][1:3]),None)
for j in xrange(len(result)):
if temp[k][1:3] == result[j][1:3]:
u=1
break
if u==0:
#if index is None:
result.append([temp[k][0],temp[k][1],temp[k][2]])
谢谢你的帮助
Herve
2 个回答
这里有一个简单的解决办法,使用了一个集合:
list1=[('a','b','c'),('d','e','f'),('g','h','i')]
list2=[('b','b','c'),('d','e','a'),('k','h','i')]
set1 = set([A[1:3] for A in list1])
final = list1 + [A for A in list2 if A[1:3] not in set1]
不过,如果你的 list1 和 list2 其实不是由元组组成的,那么你需要在 A[1:3] 的外面加上 tuple()。
下面是我们的 uniques 函数。它接受两个参数:l(列表)和 f(函数),返回一个去掉重复项的列表(保持原来的顺序)。重复项的定义是:b 是 a 的重复项,当且仅当 f(b) 等于 f(a)。
def uniques(l, f = lambda x: x):
return [x for i, x in enumerate(l) if f(x) not in [f(y) for y in l[:i]]]
我们将 lastTwo 定义如下:
lastTwo = lambda x: x[-2:]
对于你的问题,我们这样使用它:
>>> list1
[('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i')]
>>> list2
[('b', 'b', 'c'), ('d', 'e', 'a'), ('k', 'h', 'i')]
>>> uniques(list1+list2, lastTwo)
[('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i'), ('d', 'e', 'a')]
如果你描述的用例经常出现,你可能想要定义
def hervesMerge(l1, l2):
return uniques(l1+l2, lambda x: x[-2:])
Identity 是我们默认的 f,但它可以是任何东西(只要它对列表中的所有元素都有效,因为这些元素可以是任何类型)。
f 可以是一个列表的总和、列表中的奇数元素、一个整数的质因数,等等。(只要记住,如果它是单射的,那就没有意义!通过常数、线性函数等进行加法,与 identity 没有什么不同,因为 f(x) 等于 f(y) 而 x 不等于 y 才是关键)
>>> list1
[(1, 2, 3, 4), (2, 5), (6, 2, 2), (3, 4), (8, 3), (1, 1, 1, 1, 1, 1, 1, 1, 1, 1)]
>>> uniques(list1, sum)
[(1, 2, 3, 4), (2, 5), (8, 3)]
>>> uniques(list1, lambda x: reduce(operator.mul, x)) #product
[(1, 2, 3, 4), (2, 5), (3, 4), (1, 1, 1, 1, 1, 1, 1, 1, 1, 1)]
>>> uniques([1,2,3,4,1,2]) #defaults to identity
[1, 2, 3, 4]
你似乎对速度有些担心,但我的回答主要关注的是简洁性和灵活性,而没有显著(或任何?)的速度提升。对于更大的列表,如果速度是个问题,你需要利用可哈希检查和 list1 与 list2 已知没有重复项的事实。
>>> s = frozenset(i[-2:] for i in list1)
>>> ans = list(list1) #copy list1
>>> for i in list2:
if i[-2:] not in s: ans.append(i)
>>> ans
[('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i'), ('d', 'e', 'a')]
或者允许无序
>>> d = dict()
>>> for i in list2 + list1:
d[i[-2:]] = i
>>> d.values()
[('d', 'e', 'f'), ('a', 'b', 'c'), ('g', 'h', 'i'), ('d', 'e', 'a')]
--编辑--
你应该总是能够避免在问题中提到的那种不符合 Python 风格的循环。这里是你原来的代码,循环部分已经修改:
for k in temp:
u=0
for j in result:
if k[1:3] == j[1:3]:
u=1
break
if u==0:
#if index is None:
result.append([k[0],k[1],k[2]]) // k
result 和 temp 是可迭代的,对于任何可迭代的对象,你可以直接放入 for 循环中而不需要改变。如果出于某种原因你确实需要索引(虽然在这个例子中并不需要,但我上面有一个例子),你可以使用 enumerate。