如果给出一个字典来表示图形,其中顶点是键,值是列表,其条目包含邻居顶点和两个顶点之间的权重,如何以递增的顺序返回边缘列表而不重复?例如,我可能会得到以下字典......:
{“A”:[[“B”,10],[“D”,5]],“B”:[[“A”,10],[“C”,5]],“C”:[ [“B”,5],[“D”,15]],“D”:[[“C”,15],[“A”,5]]}。
此外,我只允许导入副本库,因此我可以复制一个列表并使用deepcopy()创建具有相同元素的新对象。
现在,我正在尝试将字典转换为列表,因为我认为对列表中的元素进行排序可能更容易,并删除重复的边缘。所以目前我有以下内容(图表是字典,在这种情况下是我上面提供的字典)...
def edge_get(graph):
input_list = []
sorted_list = []
for key, value in graph.items():
temp = [key,value]
input_list.append(temp)
print(input_list)
打印出......
[['A',[['B',10],['D',5]]],['B',[['A',10],['C',5]]],[ 'C',[['B',5],['D',15]]],['D',[['C',15],['A',5]]]]
我想把它输出:
[['A','B',10],['A','D',5],['B','A',10],['B','C',5] ,. ..
我想如果我可以这样得到它,我可以比较列表中每个列表的第三个元素,如果它们是相同的,检查其他元素是否匹配(相同的边缘)。基于此,我可以将其添加到最终列表中或忘记它并继续前进。
对于这个例子,最终目标是:
[['A','D'],['B','C'],['A','B'],['C','D']]
因此,您有一个将图形表示为邻接列表的dict,并且您希望将该邻接列表转换为边缘列表。
你可以使用嵌套列表理解来做到这一点:
graph = {"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}
edges = [(src, dst, weight) for src, adjs in graph.items() for dst, weight in adjs]
# edges = [('A', 'B', 10), ('A', 'D', 5), ('B', 'A', 10), ('B', 'C', 5), ('C', 'B', 5), ('C', 'D', 15), ('D', 'C', 15), ('D', 'A', 5)]
然后你可以通过转换为dict来消除重复边缘,请注意,如果你有重复冲突权重的边缘,这将任意选择一个权重:
uniques = {frozenset([src, dst]): weight for src, dst, weight in edges}
# uniques = {frozenset({'B', 'A'}): 10, frozenset({'A', 'D'}): 5, frozenset({'B', 'C'}): 5, frozenset({'C', 'D'}): 15}
然后使用sorted排序边缘:
sorted_uniques = sorted(uniques.items(), key=lambda v: v[1])
# sorted_uniques = [(frozenset({'A', 'D'}), 5), (frozenset({'C', 'B'}), 5), (frozenset({'A', 'B'}), 10), (frozenset({'C', 'D'}), 15)]
最后,要获得所需结构的结果,您只需执行以下操作:
result = [sorted(e) for e, weight in sorted_uniques]
# result = [['A', 'D'], ['B', 'C'], ['A', 'B'], ['C', 'D']]
您可以在frozenset
的帮助下将每个边缘表示为set
并过滤边缘重复:
G = {"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}
edges = {(frozenset((k, i)), j) for k, v in G.items()
for i, j in v}
[sorted(i) for i, _ in sorted(edges, key=lambda x: x[1])]
# [['B', 'C'], ['A', 'D'], ['A', 'B'], ['C', 'D']]
您可以使用itertools.product
生成密钥与每个相关子列表的组合。如果您对每个组合的字符串组件进行排序和解包,那么您将获得所需的初始输出。从那里,您可以先按重量值排序整个列表,然后按顶点排序,以获得有序列表。如果使用步长值对该列表进行切片,则可以删除重复项。然后你可以删除权重值来获得最终输出的对列表。
您可以稍微整合下面的步骤,但这会通过您的问题中列出的步骤进行,以便更容易理解。
from itertools import product
from operator import itemgetter
d = {"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}
combos = [[*sorted([c1, c2]), n] for k, v in d.items() for c1, [c2, n] in product(k, v)]
print(combos)
# [['A', 'B', 10], ['A', 'D', 5], ['A', 'B', 10], ['B', 'C', 5], ['B', 'C', 5], ['C', 'D', 15], ['C', 'D', 15], ['A', 'D', 5]]
ordered = sorted(combos, key=itemgetter(2, 0, 1))[::2]
print(ordered)
# [['A', 'D', 5], ['B', 'C', 5], ['A', 'B', 10], ['C', 'D', 15]]
pairs = [o[:-1] for o in ordered]
print(pairs)
# [['A', 'D'], ['B', 'C'], ['A', 'B'], ['C', 'D']]
编辑(没有进口):
每条评论突出显示在您的解决方案中使用导入的限制,这里是原始版本的修改版本。差异是itertools.product
的替换与列表理解,完成相同的事情和用lambda替换operator.itemgetter
。
d = {"A": [["B",10], ["D",5]], "B": [["A",10], ["C",5]], "C": [["B",5],["D",15]], "D": [["C",15], ["A",5]]}
combos = [[*sorted([k, c]), n] for k, v in d.items() for c, n in v]
print(combos)
# [['A', 'B', 10], ['A', 'D', 5], ['A', 'B', 10], ['B', 'C', 5], ['B', 'C', 5], ['C', 'D', 15], ['C', 'D', 15], ['A', 'D', 5]]
ordered = sorted(combos, key=lambda x: (x[2], x[0], x[1]))[::2]
print(ordered)
# [['A', 'D', 5], ['B', 'C', 5], ['A', 'B', 10], ['C', 'D', 15]]
pairs = [o[:-1] for o in ordered]
print(pairs)
# [['A', 'D'], ['B', 'C'], ['A', 'B'], ['C', 'D']]