我有一个方法,该方法采用边列表,边具有以下形式:(v1,v2,capacity)
并返回以下形式的字典:
dico = {v1:{v2:capacity,v3:capacity} v2:...}
此dico
代表图形
我想通过理解的方式来定义这个dico,但是我真的很受阻,我什至不知道我们能做到这一点,所以有人可以告诉我是否可能吗? 这是我的功能:
def _init_from_edges(self, edges):
self._G={}
for e in edges:
if e[0] in self._G:
self._G[e[0]][e[1]]=e[2]
else:
self._G[e[0]]={e[1]:e[2]}
答案 0 :(得分:1)
您的代码不能轻松利用dict
的理解能力,因为它实际上是一个多变量(键不具有一个值,而是多个)。
您可以简化代码with collections.defaultdict
:
from collections import defaultdict
def _init_from_edges(self, edges):
self._G = defaultdict(dict)
for v1, v2, capacity in edges:
self._G[v1][v2] = capacity
# Optional: Remove defaultdict behaviors after building
self._G = dict(self._G)
使用defaultdict(dict)
意味着当字典中没有键时,它会立即以全新的dict
创建,因此您根本不需要执行成员资格测试。
请注意,我还使用了对命名变量的解包,而不是重复索引,以使代码更具自记录性。
通过实际的dict
理解才能实现此目的的唯一方法是:
edges
一次,以收集给定v2
的所有capacity
/ v1
对(但这是O(n**2)
,所以很不好知道edges
是否可以大)v1
的所有值打包在一起,这样就可以一次构造所有子dict
。由于选项#1通常非常浪费,因此唯一可行的方法是作为dict
理解而无需一遍又一遍地重新扫描edges
是选项#2,您可以 在O(n log n)
中对followed by itertools.groupby
进行排序:
from itertools import groupby
from operator import itemgetter
def _init_from_edges(self, edges):
self._G = {v1: {v2: capacity for _, v2, capacity in grp}
for v1, grp in groupby(sorted(edges, key=itemgetter(0)),
key=itemgetter(0))}
这需要O(n log n)
来对edges
进行排序(如果edges
已经被排序,Python的TimSort意味着它更接近O(n)
的工作),然后O(n)
可以工作将结果分组。比{v1: {v2: capacity for v, v2, capacity in edges if v == v1} for v1, _, _ in edges}
快,但仍比使用defaultdict
的非理解方法(在所有情况下均为O(n)
)慢。
答案 1 :(得分:0)
这有点令人费解,但似乎可行:
edges = [(1, 2, 3),
(1, 3, 4),
(2, 1, 5),
(2, 3, 6),
(2, 2, 7)]
dico = {v1: {v2: cap for v, v2, cap in edges if v == v1} for v1, _, _ in edges}
# {1: {2: 3, 3: 4}, 2: {1: 5, 2: 7, 3: 6}}
基本上,每个v1
都将edges
中的每个键:值对与该v1
相加。外部理解不需要v2
或cap
,因此仅使用下划线忽略这些值。内循环需要将v1
的 值与外循环的值进行比较,这就是为什么使用不同名称的原因。