在 Python 元组列表中查找重复项
Posted
技术标签:
【中文标题】在 Python 元组列表中查找重复项【英文标题】:Find duplicate items within a list of list of tuples Python 【发布时间】:2013-07-05 07:02:54 【问题描述】:我想从下面给定的列表中找到匹配的项目。我的列表可能超级大。
元组“N1_10”中的第一个项目被复制并与另一个数组中的另一个项目匹配
ListA 中第一个数组中的元组 ('N1_10', 'N2_28')
ListA 中第二个数组中的元组('N1_10', 'N3_98')
ListA = [[('N1_10', 'N2_28'), ('N1_35', 'N2_44')],
[('N1_22', 'N3_72'), ('N1_10', 'N3_98')],
[('N2_33', 'N3_28'), ('N2_55', 'N3_62'), ('N2_61', 'N3_37')]]
我想要的输出是
输出 --> [('N1_10','N2_28','N3_98') , ....
和其余任何匹配的
密钥将进入相同的元组]
如果你们认为,改变 ListA 的数据结构是更好的选择,请随时提出建议! 感谢您的帮助!
简化版
列表 A = [[(a,x),(b,k),(c,l),(d,m)],[(e,d),(a,p),(g,s)],[...],[...]....]
wantedOutput --> [(a,x,p),(b,k),(c,l),(d,m,e), (g,s).....]
【问题讨论】:
等等,你是怎么得到输出的? 我还没有得到输出。这就是我在这里问的原因:) 我的意思是,输出是什么因素?如果你明白我的意思,我没有看到模式 哦,等等,我明白了。是否只有元组中的第一项与其他内容重复? 那个简化版有帮助,谢谢:) 【参考方案1】:更新:重新阅读您的问题后,您似乎正在尝试创建等价类,而不是收集键的值。如果
[[(1, 2), (3, 4), (2, 3)]]
应该变成
[(1, 2, 3, 4)]
,那么您将需要将输入解释为图形并应用连通分量算法。您可以将您的数据结构转换为adjacency list 表示并使用广度优先或深度优先搜索来遍历它,或者遍历您的列表并构建disjoint sets。无论哪种情况,您的代码都会突然涉及大量与图形相关的复杂性,并且很难根据输入的顺序提供任何输出顺序保证。这是一个基于广度优先搜索的算法:
import collections
# build an adjacency list representation of your input
graph = collections.defaultdict(set)
for l in ListA:
for first, second in l:
graph[first].add(second)
graph[second].add(first)
# breadth-first search the graph to produce the output
output = []
marked = set() # a set of all nodes whose connected component is known
for node in graph:
if node not in marked:
# this node is not in any previously seen connected component
# run a breadth-first search to determine its connected component
frontier = set([node])
connected_component = []
while frontier:
marked |= frontier
connected_component.extend(frontier)
# find all unmarked nodes directly connected to frontier nodes
# they will form the new frontier
new_frontier = set()
for node in frontier:
new_frontier |= graph[node] - marked
frontier = new_frontier
output.append(tuple(connected_component))
但是,不要在不理解的情况下复制它;了解它在做什么,或者编写自己的实现。您可能需要能够维护这一点。 (我会使用伪代码,但 Python 实际上已经和伪代码一样简单了。)
如果我对您问题的原始解释是正确的,并且您的输入是您想要聚合的键值对的集合,那么这是我的原始答案:
原答案
import collections
clusterer = collections.defaultdict(list)
for l in ListA:
for k, v in l:
clusterer[k].append(v)
output = clusterer.values()
defaultdict(list)
是一个 dict
,它会自动创建一个 list
作为任何不存在的键的值。循环遍历所有元组,收集与同一键匹配的所有值,然后从 defaultdict 创建一个 (key, value_list) 对的列表。
(这段代码的输出和你指定的形式不太一样,但我相信这个形式更有用。如果你想改变形式,那应该是一件简单的事情。)
【讨论】:
首先,这段代码的输出是一个字符列表。你应该使用append
而不是+=
。其次,(如果您使用附加),代码会丢失关系信息。我想我知道你想做什么,但这是不对的。
@korylprince:废话,append
是对的。我的错误。另一方面,我最初将这个问题阅读为试图聚合一堆键值对,但在第二次阅读时,它似乎是一个图的连接组件分析。我将使用连接组件算法更新我的响应。
@user2357112 ,是的,它是一种邻接矩阵列表表示。如果您有时间,请告诉如何更改它?
@Peter:我添加了一个基于广度优先搜索的算法的示例实现。【参考方案2】:
输出顺序重要吗?这是我能想到的最简单的方法:
ListA = [[('N1_10', 'N2_28'), ('N1_35', 'N2_44')],[('N1_22', 'N3_72'), ('N1_10', 'N3_98')],
[('N2_33', 'N3_28'), ('N2_55', 'N3_62'), ('N2_61', 'N3_37')]]
idx = dict()
for sublist in ListA:
for pair in sublist:
for item in pair:
mapping = idx.get(item,set())
mapping.update(pair)
idx[item] = mapping
for subitem in mapping:
submapping = idx.get(subitem,set())
submapping.update(mapping)
idx[subitem] = submapping
for x in set([frozenset(x) for x in idx.values()]):
print list(x)
输出:
['N3_72', 'N1_22']
['N2_28', 'N3_98', 'N1_10']
['N2_61', 'N3_37']
['N2_33', 'N3_28']
['N2_55', 'N3_62']
['N2_44', 'N1_35']
【讨论】:
我很确定这是有问题的。每当处理输入对时,对应于该对的第二项的集合被替换为对应于第一项的集合。如果第二个项目已经存储了关联,则会丢失数据。 其实我对 python 还是很陌生。你能解释更多关于forzenset的信息吗?我现在用我的数据集确认,每个元组数组中没有重复的数据,但是,对于整个大 listA 中的不同数组,项目可能重复。 @user2357112 很好。更新了代码以解决此问题和可读性。 @Peter -frozenset
只是一个无法修改的 set
。我使用那行代码是因为你不能在 python 中拥有 set
s 的 set
(因为 set
不可散列)但你可以拥有 frozenset
s 的 set
。跨度>
【参考方案3】:
tupleList = [(1, 2), (3, 4), (1, 4), (3, 2), (1, 2), (7, 9), (9, 8), (5, 6)]
newSetSet = set ([frozenset (aTuple) for aTuple in tupleList])
setSet = set ()
while newSetSet != setSet:
print '*'
setSet = newSetSet
newSetSet = set ()
for set0 in setSet:
merged = False
for set1 in setSet:
if set0 & set1 and set0 != set1:
newSetSet.add (set0 | set1)
merged = True
if not merged:
newSetSet.add (set0)
print [tuple (element) for element in setSet]
print [tuple (element) for element in newSetSet]
print
print [tuple (element) for element in newSetSet]
# Result: [(1, 2, 3, 4), (5, 6), (8, 9, 7)]
【讨论】:
已测试,为了速度,取出打印语句。 从技术上讲,它可以工作(我认为),但它的性能会很糟糕。在最坏的情况下,它会在指数时间内运行,因为它最终可能会遍历 2 个或更多输入元素的所有可能组合。 每执行一次while循环,至少发生了一次合并,这使得newSetSet的基数少了一个。因此,对于三个嵌套循环,我希望 O (n^3) 而不是 O (exp (n)。但我很可能忽略了一些事情。如果是这样,请解释一下。 一个集合每次迭代可以与许多其他集合合并,而不仅仅是一个。这些合并不会产生一个大的合并集;他们产生了一堆部分合并的集合。发生这种情况时,newSetSet 实际上可以增长。尝试使用tupleList = [(x, y) for x in range(n) for y in range(x)]
获取n
的各种值。以上是关于在 Python 元组列表中查找重复项的主要内容,如果未能解决你的问题,请参考以下文章