如果我有一个元组列表,每个元组代表变量a
,b
和c
,我怎样才能消除多余的元组?
冗余元组是a
和b
简单互换的元组,但c
是相同的。所以对于这个例子:
tups = [(30, 40, 50), (40, 30, 50), (20, 48, 52), (48, 20, 52)]
我的最终列表应该只包含一半的条目。一个可能的输出:
tups = [(30, 40, 50), (20, 48, 52)]
另一个
tups = [(40, 30, 50), (20, 48, 52)]
等
有一种简单的Pythonic方法吗?
我尝试使用套装,但(30, 40, 50)
与(40, 30, 50)
不同,但对我来说,这些是多余的,我只想保留其中一个(不重要) ,但如果我可以选择,我更喜欢低价值到高价值的订单。如果有一种方法可以对元组的前2个元素进行排序,那么使用该集就可以了。
我相信我可以将一个有效的解决方案(可能将元组转换为列表作为中间步骤),但我只是想看看是否有一个简单而明显的方法可以做到这一点我是不熟悉。
PS:这个问题部分由PE #39推动。但即使不考虑这个PE问题,我现在只是好奇如何轻松地(或者如果)这样做。
修改:
为那些不熟悉PE#39的人提供一些背景 - a
,b
和c
代表直角三角形的边,所以我' m检查是否a**2 + b**2 == c**2
,显然a
和b
的顺序并不重要。
答案 0 :(得分:7)
set([(a,b,c) if a<b else (b,a,c) for a,b,c in tups])
答案 1 :(得分:4)
tups = [(30, 40, 50), (40, 30, 50), (20, 48, 52), (48, 20, 52)]
no_duplicates = list(set(tuple(sorted(tup)) for tup in tups))
当然这是假设每个元组的第3个元素将始终是每个元组中的最大元素,否则,执行此操作:
no_duplicates = list(set(tuple(sorted(tup[:2])) + (tup[2],) for tup in tups))
正如WolframH所建议的,表达式tuple(sorted(tup[:2])) + (tup[2],)
可以写成tuple(sorted(tup[:2])) + tup[2:]
,这是有利的,因为它可以推广到tuple(sorted(tup[:i])) + tup[i:]
,其中i
可以是任何一点一个人想要将已排序的元素与未排序的元素分开。
答案 2 :(得分:4)
从你的问题来看,你的元组的前两个元素似乎在元组中形成一个子单元。因此,将数据重组为元组和第三个数字的元组似乎是有意义的,其中第一个元组是按排序顺序排列的前两个数字。然后你可以自然地使用集合:
>>> newTups = [(tuple(sorted([a, b])), c) for a, b, c in tups]
>>> newTups
[((30, 40), 50), ((30, 40), 50), ((20, 48), 52), ((20, 48), 52)]
>>> set(newTups)
set([((20, 48), 52), ((30, 40), 50)])
答案 3 :(得分:2)
将每个元组转换为frozenset
,然后创建set
这些冻结。
tups = [(30, 40, 50), (40, 30, 50), (20, 48, 52), (48, 20, 52)]
frozen_sets = { frozenset(x) for x in tups }
tups2 = [tuple(x) for x in frozen_sets]
这可行,因为frozenset([1,2,3]) == frozenset([3,1,2])
与元组相比,(1,2,3) != (3,1,2)
。
您必须将元组转换为frozenset
而不是简单set
,因为当您尝试将一个集合作为另一个集合的成员时,会出现以下错误:
TypeError: unhashable type: 'set'
frozenset
可以播放,因此请避免此问题。
答案 4 :(得分:1)
如果你不关心前两个元素的顺序,你真的不想使用3-uples:只需转换为一个新的数据结构,它丢弃你不需要的信息。
result = {({x[0],x[1]},x[2]) for x in tups}