|
1 | 1 | from collections import MappingView,KeysView,ValuesView,ItemsView
|
| 2 | + |
2 | 3 | from nodes import Nodes
|
3 | 4 | from edges import Edges
|
4 | 5 | from adjacency import Adjacency
|
|
7 | 8 | class Subgraph(object):
|
8 | 9 | # __slots__ = ('_nodedata','_adjacency','data')
|
9 | 10 | def __init__(self, graph, subnodes):
|
| 11 | + # TODO Can we replace nbunch_iter with set(subnodes) & set(graph)? |
| 12 | + # We lose the Error messages... |
10 | 13 | self._subnodes = set(self._nbunch_iter(graph, subnodes))
|
11 |
| - self.data = graph.data |
12 |
| - self._nodedata = SubNodeData(self._subnodes, graph._nodedata) |
| 14 | + self._nodedata = SubNbrDict(self._subnodes, graph._nodedata) |
13 | 15 | self._adjacency = SubAdjacency(self._subnodes, graph._adjacency)
|
14 |
| - self.test=self._adjacency |
| 16 | + self.data = graph.data |
15 | 17 | self.n = Nodes(self._nodedata, self._adjacency)
|
16 | 18 | self.e = Edges(self._nodedata, self._adjacency)
|
17 |
| - self.a = Adjacency(self._adjacency) |
| 19 | + self.a = self._adjacency |
18 | 20 | def __repr__(self):
|
19 | 21 | return '{0.__class__.__name__}({1})'.format(self,list(self._subnodes))
|
| 22 | + def __iter__(self): |
| 23 | + return iter(self._subnodes) |
| 24 | + def __len__(self): |
| 25 | + return len(self._subnodes) |
| 26 | + |
20 | 27 | @staticmethod
|
21 | 28 | def _nbunch_iter(graph, nbunch=None):
|
22 | 29 | if nbunch is None: # include all nodes via iterator
|
@@ -46,41 +53,66 @@ def bunch_iter(nlist, adj):
|
46 | 53 |
|
47 | 54 |
|
48 | 55 |
|
49 |
| -class SubNodeData(MappingView): |
| 56 | +class SubNbrDict(MappingView): |
| 57 | + # __slots__= ["_nodes","_mapping","_cache"] |
50 | 58 | def __init__(self, nodes, mapping):
|
51 |
| - self._nodes = nodes |
| 59 | + # In nodes to be in subgraph, in mapping to be in nbrs. |
| 60 | + # So need intersection of nodes with mapping... |
| 61 | + self._nodes = set(nodes) & set(mapping) |
52 | 62 | self._mapping = mapping
|
53 |
| - def __iter__(self): |
54 |
| - for n in self._nodes: |
55 |
| - yield n |
56 |
| - def __getitem__(self, key): |
57 |
| - if key in self._nodes: |
58 |
| - return self._mapping[key] |
59 |
| - else: |
60 |
| - raise KeyError |
61 |
| - def __contains__(self, key): |
62 |
| - return key in self._nodes |
| 63 | + self._cache = {} |
63 | 64 | def __repr__(self):
|
64 |
| - return '{}'.format(self._nodes) |
| 65 | + return '{0.__class__.__name__}({0._nodes}, {0._mapping})'.format(self) |
| 66 | + def __iter__(self): |
| 67 | + return iter(self._nodes) |
| 68 | + def __getitem__(self, n): |
| 69 | + if n in self._nodes: |
| 70 | + # Datadicts are read/write so no wrapper for mapping[n] |
| 71 | + return self._mapping[n] |
| 72 | + raise KeyError |
| 73 | + def __contains__(self, n): |
| 74 | + return n in self._nodes |
65 | 75 | def __len__(self):
|
66 | 76 | return len(self._nodes)
|
| 77 | + |
67 | 78 | def keys(self):
|
68 |
| - return KeysView(self._nodes) |
| 79 | + return self._nodes.keys() |
| 80 | + def data(self): |
| 81 | + # Datadicts are read/write so no wrapper for mapping[n] |
| 82 | + for n in self._nodes - set(self._cache.keys()): |
| 83 | + self._cache[n] = self._mapping[n] |
| 84 | + return self._cache.values() |
69 | 85 | def items(self):
|
70 |
| - return dict((k,v) for (k,v) in self._mapping.items() if k in self._nodes |
71 |
| -).items() |
| 86 | + # Datadicts are read/write so no wrapper for mapping[n] |
| 87 | + for n in self._nodes - set(self._cache.keys()): |
| 88 | + self._cache[n] = self._mapping[n] |
| 89 | + return self._cache.items() |
72 | 90 |
|
73 |
| -class SubAdjacency(SubNodeData): |
| 91 | +class SubAdjacency(SubNbrDict): |
| 92 | + #__slots__ = ["_nodes","_mapping","_cache"] |
74 | 93 | def __iter__(self):
|
75 | 94 | for n in self._nodes:
|
76 |
| - yield (n, SubNodeData(self._nodes, self._mapping[n]).items()) |
77 |
| - def __getitem__(self, key): |
78 |
| - if key in self._nodes: |
79 |
| - return SubNodeData(self._nodes, self._mapping[key]) |
80 |
| - else: |
81 |
| - raise KeyError |
82 |
| - def __repr__(self): |
83 |
| - return '{}'.format(self.items()) |
| 95 | + if n in self._cache: |
| 96 | + yield (n, self._cache[n]) |
| 97 | + else: |
| 98 | + # NbrDicts are read-only so use wrapper for mapping[n] |
| 99 | + self._cache[n] = nd = SubNbrDict(self._nodes, self._mapping[n]) |
| 100 | + yield (n, nd) |
| 101 | + def __getitem__(self, n): |
| 102 | + if n in self._cache: |
| 103 | + return self._cache[n] |
| 104 | + if n in self._nodes: |
| 105 | + # NbrDicts are read-only so use wrapper for mapping[n] |
| 106 | + self._cache[n] = nd = SubNbrDict(self._nodes, self._mapping[n]) |
| 107 | + return nd |
| 108 | + raise KeyError |
| 109 | + def data(self): |
| 110 | + # NbrDicts are read-only so use wrapper for mapping[n] |
| 111 | + for n in self._nodes - set(self._cache.keys()): |
| 112 | + self._cache[n] = SubNbrDict(self._nodes, self._mapping[n]) |
| 113 | + return self._cache.values() # Not readonly datadict |
84 | 114 | def items(self):
|
85 |
| - for n in self._nodes: |
86 |
| - yield (n, dict(SubNodeData(self._nodes, self._mapping[n]).items())) |
| 115 | + # NbrDicts are read-only so use wrapper for mapping[n] |
| 116 | + for n in self._nodes - set(self._cache.keys()): |
| 117 | + self._cache[n] = SubNbrDict(self._nodes, self._mapping[n]) |
| 118 | + return self._cache.items() |
0 commit comments