TypeError: 'generator' object is not subscriptable when indexing networkx.all_pairs_shortest_path_length result
0 reputation · 26 Feb 2021, 11:59 UTC
0 reputation · 26 Feb 2021, 11:59 UTC
In NetworkX 2.x the function all_pairs_shortest_path_length(G) returns a dictionary mapping each source node to a dictionary of target‑distance pairs, allowing direct indexing such as lengths[s][t]. Starting with version 3.0 the function was changed to return a lazy generator yielding (source, {target: length, ...}) tuples to reduce memory consumption for large graphs.
This change breaks existing code that assumes a subscriptable mapping, raising TypeError: 'generator' object is not subscriptable. While the iterator improves scalability, it introduces a backward‑compatibility tension for users who rely on the eager dict behavior.
NetworkX maintainers have not yet settled on whether to retain the iterator as the default return type, provide a compatibility shim that restores the dict behavior, or expose a helper such as to_dict() that users can call explicitly.
all_pairs_shortest_path_length return a dict by default for backward compatibility?to_dict() converter on the generator be a sufficient compromise without altering the default API?dict() rather than modify the library’s return type?35775 reputation · 26 Feb 2021, 18:10 UTC
The TypeError: 'generator' object is not subscriptable occurs because nx.all_pairs_shortest_path_length(G) no longer returns a nested dictionary. In NetworkX 3.x the function yields a generator of tuples (source, {target: length, …}) to save memory. Attempting to index that generator directly (e.g., result[s][t]) triggers the error.
generator.TypeError: 'generator' object is not subscriptable.nx.shortest_path_length for a single pair works.The change was intentional to reduce memory usage for large graphs. The API shift breaks legacy code that assumed a dict.
Verify the NetworkX version:
import networkx as nx
print(nx.__version__)If you are on 3.x and need a dict for quick look‑ups, convert the generator:
lengths = dict(nx.all_pairs_shortest_path_length(G))
# Now you can index:
distance = lengths[source][target]For a single source‑target pair, call the more direct API:
dist = nx.shortest_path_length(G, source, target)If you need to iterate lazily, consume the generator directly:
for src, dists in nx.all_pairs_shortest_path_length(G):
if src == source:
print(dists[target])
breakCould you confirm which NetworkX version you are using? If you are on 2.x, the function should already return a dict and the error would indicate a different issue.
Use comments to ask for clarification. Post a solution as an answer.
7,130 reputation · 26 Feb 2021, 15:41 UTC
In NetworkX 3.x all_pairs_shortest_path_length(G) returns a generator that yields tuples of the form (source, {target: length, …}). This design keeps memory usage low because you can process each source node one at a time instead of building a full V×V dictionary.
When you only need a distance for one source–target pair you can pull it out directly from the generator:
for src, dists in nx.all_pairs_shortest_path_length(G):
if src == source_node:
print(dists[target_node])
break
Using next() with a generator expression also works:
dist = next(d for s, d in nx.all_pairs_shortest_path_length(G) if s == source_node)[target_node]
If you require random look‑ups later, wrap the call in dict():
lengths = dict(nx.all_pairs_shortest_path_length(G))
# now you can index: lengths[s][t]
Be cautious: this consumes the entire generator and can raise MemoryError on very large graphs, defeating the original memory‑saving intent.
For a single pair, the dedicated API is simpler and faster:
dist = nx.shortest_path_length(G, source_node, target_node)
It avoids any generator overhead and is the recommended approach when you only need one distance.