Skip to content

Commit 019fa00

Browse files
committed
Adjust set operations for Views. Restructure edges.py
In nodes.py: - add __rand__ and friends so that "set|view" works like "view|set" - took care of some fixmes in other set operations - need to figure out how to do repr like ItemsView In edges.py: - Views had no set operations. I created BaseEdgeView subclass of Set. - Put all functions that depend on "directed" into UndirectedEdges. - Edges subclasses from UndirectedEdges and Set.
1 parent 57e2983 commit 019fa00

File tree

2 files changed

+78
-66
lines changed

2 files changed

+78
-66
lines changed

edges.py

+62-59
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,51 @@
1-
from collections import MappingView
1+
from collections import MappingView, Set
22
from networkx.exception import NetworkXError
33

44

5+
class BaseEdgeView(Set):
6+
__slots__ = ["_edgesobj"]
7+
def __init__(self, edgesobj):
8+
self._edgesobj = edgesobj
9+
def __repr__(self):
10+
return '{0.__class__.__name__}({1})'.format(self,list(self))
11+
def __len__(self):
12+
return len(self._edgesobj)
13+
# Set also demands __iter__ and __contains__ be defined.
14+
15+
class EdgeKeys(BaseEdgeView):
16+
__slots__ = ["_edgesobj"]
17+
def __iter__(self):
18+
return iter(self._edgesobj)
19+
def __contains__(self, key):
20+
u,v = key
21+
return v in self._edgesobj._adj[u]
22+
23+
class EdgeData(BaseEdgeView):
24+
__slots__ = ["_edgesobj"]
25+
def __iter__(self):
26+
for e,d in self._edgesobj._items():
27+
yield d
28+
def __contains__(self, data):
29+
# Do we need/want to provide ability to look up a datadict?
30+
# need to look at all data
31+
for d in self:
32+
if d == data:
33+
return True
34+
return False
35+
36+
class EdgeItems(BaseEdgeView):
37+
__slots__ = ["_edgesobj"]
38+
def __iter__(self):
39+
return self._edgesobj._items()
40+
def __contains__(self, key):
41+
adj = self._edgesobj._adj
42+
(u,v),d = key
43+
return v in adj[u] and adj[u][v] == d
44+
45+
546
class UndirectedEdges(object):
6-
__slots__ = ('_adj','_node')
7-
def __init__(self, node, adj):
8-
self._adj = adj
9-
self._node = node
47+
def __len__(self):
48+
return sum(len(nbrs) for n, nbrs in self._adj.items()) // 2
1049
def __iter__(self):
1150
seen = set()
1251
nodes_nbrs = self._adj.items()
@@ -16,8 +55,6 @@ def __iter__(self):
1655
yield (n, nbr)
1756
seen.add(n)
1857
del seen
19-
def __len__(self):
20-
return sum(len(nbrs) for n, nbrs in self._adj.items()) // 2
2158
def _items(self):
2259
seen = set()
2360
nodes_nbrs = self._adj.items()
@@ -27,35 +64,6 @@ def _items(self):
2764
yield (n,nbr),ddict
2865
seen.add(n)
2966
del seen
30-
31-
class EdgeKeys(UndirectedEdges):
32-
def __repr__(self):
33-
return '{})'.format(list(self))
34-
35-
class EdgeData(UndirectedEdges):
36-
def __iter__(self):
37-
for e,d in self._items():
38-
yield d
39-
def __repr__(self):
40-
return '{})'.format(list(self))
41-
def __contains__(self, key):
42-
# need to look at all data
43-
for k in self:
44-
if k == key:
45-
return True
46-
return False
47-
48-
class EdgeItems(UndirectedEdges):
49-
def __iter__(self):
50-
return self._items()
51-
def __repr__(self):
52-
return '{})'.format(list(self))
53-
def __contains__(self, key):
54-
(u,v),d = key
55-
return v in self._adj[u] and self._adj[u][v] == d
56-
57-
58-
class Edges(UndirectedEdges):
5967
def __contains__(self, key):
6068
u,v = key
6169
return v in self._adj[u]
@@ -65,26 +73,7 @@ def __getitem__(self, key):
6573
return self._adj[u][v]
6674
except TypeError:
6775
raise NetworkXError('bad edge key: use edge key = (u,v)')
68-
def __and__(self, other):
69-
return set(self) & set(other)
70-
def __or__(self, other):
71-
return set(self) | set(other)
72-
def __xor__(self, other):
73-
return set(self) ^ set(other)
74-
def __sub__(self, other):
75-
return set(self) - set(other)
76-
def __repr__(self):
77-
return '{0.__class__.__name__}({1})'.format(self,list(self))
78-
def keys(self):
79-
return EdgeKeys(self._node, self._adj)
80-
def data(self):
81-
return EdgeData(self._node, self._adj)
82-
def items(self):
83-
return EdgeItems(self._node, self._adj)
84-
def selfloops(self):
85-
return ((n, n)
86-
for n, nbrs in self._adj.items() if n in nbrs)
87-
76+
# Mutating Methods
8877
def add(self, u, v, attr_dict=None, **attr):
8978
if attr_dict is None:
9079
attr_dict = attr
@@ -106,8 +95,6 @@ def add(self, u, v, attr_dict=None, **attr):
10695
datadict.update(attr_dict)
10796
self._adj[u][v] = datadict
10897
self._adj[v][u] = datadict
109-
110-
11198
def update(self, ebunch, attr_dict=None, **attr):
11299
# set up attribute dict
113100
if attr_dict is None:
@@ -140,7 +127,6 @@ def update(self, ebunch, attr_dict=None, **attr):
140127
datadict.update(dd)
141128
self._adj[u][v] = datadict
142129
self._adj[v][u] = datadict
143-
144130
def remove(self, u, v):
145131
try:
146132
del self._adj[u][v]
@@ -151,3 +137,20 @@ def remove(self, u, v):
151137
def clear(self):
152138
for n in self._adj:
153139
self._adj[n].clear()
140+
141+
class Edges(UndirectedEdges, Set):
142+
__slots__ = ('_adj','_node')
143+
def __init__(self, node, adj):
144+
self._adj = adj
145+
self._node = node
146+
def __repr__(self):
147+
return '{0.__class__.__name__}({1})'.format(self,list(self))
148+
def keys(self):
149+
return EdgeKeys(self)
150+
def data(self):
151+
return EdgeData(self)
152+
def items(self):
153+
return EdgeItems(self)
154+
def selfloops(self):
155+
return ((n, n)
156+
for n, nbrs in self._adj.items() if n in nbrs)

nodes.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
class NodeKeys(KeysView):
55
def __repr__(self):
6+
# If we remove this def, the result is:
7+
# return '{0.__class__.__name__}({1})'.format(self,self._mapping)
68
return '{}'.format(list(self._mapping))
79

810
class NodeData(ValuesView):
@@ -25,7 +27,7 @@ def __iter__(self):
2527
def __contains__(self, key):
2628
return key in self._nodes
2729
def __repr__(self):
28-
return '{0.__class__.__name__}({1})'.format(self,list(self._nodes))
30+
return '{0.__class__.__name__}({1})'.format(self,self._nodes)
2931
def __len__(self):
3032
return len(self._nodes)
3133
def clear(self):
@@ -40,6 +42,16 @@ def __xor__(self, other):
4042
return set(self._nodes) ^ set(other)
4143
def __sub__(self, other):
4244
return set(self._nodes) - set(other)
45+
# reverse set methods (so set | me works same as me | set)
46+
def __rand__(self, other):
47+
return set(self._nodes) & set(other)
48+
def __ror__(self, other):
49+
return set(self._nodes) | set(other)
50+
def __rxor__(self, other):
51+
return set(self._nodes) ^ set(other)
52+
def __rsub__(self, other):
53+
return set(self._nodes) - set(other)
54+
# inplace mass adds and removes
4355
def update(self, nodes, **attr):
4456
for n in nodes:
4557
try:
@@ -51,20 +63,17 @@ def update(self, nodes, **attr):
5163
self.add(n, attr_dict=None, **attr)
5264
return self
5365
def intersection_update(self, nodes):
54-
# fixme: make work for node tuples?
55-
for n in self - nodes:
66+
for n in self - set(nodes):
5667
self.discard(n)
5768
return self
5869
def symmetric_difference_update(self, nodes):
59-
# fixme: make work for node tuples?
6070
for n in nodes:
6171
if n in self:
6272
self.discard(n)
6373
else:
6474
self.add(n)
6575
return self
6676
def difference_update(self, nodes):
67-
# fixme: make work for node tuples?
6877
for n in nodes:
6978
self.discard(n)
7079
return self
@@ -77,10 +86,10 @@ def difference_update(self, nodes):
7786
def discard(self, n):
7887
adj = self._adj
7988
try:
80-
# keys handles self-loops (allow mutation later)
89+
# list handles self-loops (allow mutation later)
8190
nbrs = list(adj[n].keys())
8291
del self._nodes[n]
83-
except KeyError: # NetworkXError if n not in self
92+
except KeyError: # silently ignore if n not in self
8493
return
8594
for u in nbrs:
8695
del adj[u][n] # remove all edges n-u in graph

0 commit comments

Comments
 (0)