2 回答
TA贡献1827条经验 获得超9个赞
您的代码不能dict轻易利用推导式,因为它实际上是一个多重字典(其中一个键没有一个值,而是多个值)。
您可以简化代码有点用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)
Usingdefaultdict(dict)意味着当一个键不在字典中时,它会立即用一个全新的 创建dict,因此您根本不需要执行成员资格测试。
请注意,我还使用了对命名变量的解包而不是重复索引来使代码更具自文档性。
使这项工作具有实际dict理解力的唯一方法是:
edges为每个输入重新扫描一次以收集给定的所有v2/capacity对v1(但那是O(n**2),所以如果edges可以很大,这是一个坏主意)
v1提前将每个的所有值打包在一起,因此dict可以一次构建每个子项。
由于选项 #1 通常非常浪费,唯一可行的方法是作为一种dict理解而不需要edges一遍又一遍地重新扫描是选项 #2,您可以在O(n log n)排序后执行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},但仍比非理解方法 with 慢defaultdict(O(n)在所有情况下)。
TA贡献1810条经验 获得超4个赞
这有点令人费解,但似乎有效:
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。外部理解不需要v2or cap,所以它只使用下划线来忽略这些值。内循环需要将其值v1与外循环的值进行比较,这就是它使用不同名称的原因。
添加回答
举报