Mercurial > hg > MPIWGWeb
annotate HashTree.py @ 266:bd41c278b88a new_pro_struct
add web calendar link.
author | casties |
---|---|
date | Wed, 27 Aug 2014 14:28:27 +0200 |
parents | 7288e7729960 |
children |
rev | line source |
---|---|
27 | 1 import logging |
2 | |
3 class HashTreeNode: | |
4 """Node of a HashTree. | |
5 Has a value and keeps children in a dict indexed by key.""" | |
6 key = None | |
7 value = None | |
8 children = None | |
9 | |
10 def __init__(self, key=None, value=None, children=None): | |
11 """create node""" | |
12 self.key = key | |
13 self.value = value | |
14 self.children = children | |
15 | |
229
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
16 |
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
17 def setValue(self, val, append=True, unique=False): |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
18 """set or append to the value""" |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
19 if (self.value is not None) or append: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
20 if isinstance(self.value, list): |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
21 # old value is list |
229
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
22 if unique and val in self.value: |
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
23 logging.debug("setValue: list HAS SAME: %s"%repr(val)) |
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
24 return |
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
25 |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
26 self.value.append(val) |
229
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
27 |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
28 elif self.value is not None: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
29 # old value is scalar |
229
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
30 if unique and val == self.value: |
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
31 logging.debug("setValue: scalar IS SAME: %s"%repr(val)) |
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
32 return |
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
33 |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
34 self.value = [self.value, val] |
229
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
35 |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
36 else: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
37 # old value is None |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
38 self.value = val |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
39 |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
40 else: |
229
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
41 # old value is None |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
42 self.value = val |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
43 |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
44 |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
45 def getValue(self, onlyFirst=True, asList=False): |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
46 """get the (first) value""" |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
47 if isinstance(self.value, list): |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
48 if onlyFirst and not asList: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
49 return self.value[0] |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
50 else: |
229
d4216a848547
fixed problem that reading the project tree changes it.
casties
parents:
228
diff
changeset
|
51 return self.value[:] |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
52 else: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
53 if asList: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
54 if self.value is None: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
55 return [] |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
56 else: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
57 return [self.value] |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
58 else: |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
59 return self.value |
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
60 |
27 | 61 |
62 def getNode(self, key): | |
63 """return node under key""" | |
64 if self.children is None: | |
65 return None | |
66 else: | |
67 return self.children.get(key, None) | |
68 | |
69 | |
70 def addNode(self, node): | |
71 """add child node using key from node""" | |
72 if self.children is None: | |
73 self.children = {node.key : node} | |
74 else: | |
75 self.children[node.key] = node | |
76 | |
77 | |
105
246d87d33f25
CLOSED - # 79: sortierung der liste der projekte pro abteilung
casties
parents:
97
diff
changeset
|
78 def getSubtreeAsList(self, depthFirst=True): |
246d87d33f25
CLOSED - # 79: sortierung der liste der projekte pro abteilung
casties
parents:
97
diff
changeset
|
79 """Return the subtree as flattened list sorted by key.""" |
114
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
80 if depthFirst: |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
81 return self.getSubtreeAsListDepthFirst() |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
82 else: |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
83 return self.getSubtreeAsListBreadthFirst() |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
84 |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
85 |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
86 def getSubtreeAsListDepthFirst(self): |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
87 """Return the subtree as flattened list, depth first, sorted by key.""" |
27 | 88 if self.children is None: |
114
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
89 if self.value is None: |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
90 return [] |
105
246d87d33f25
CLOSED - # 79: sortierung der liste der projekte pro abteilung
casties
parents:
97
diff
changeset
|
91 else: |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
92 return self.getValue(asList=True) |
27 | 93 |
94 else: | |
95 if self.value is None: | |
96 sub = [] | |
97 else: | |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
98 sub = self.getValue(asList=True) |
27 | 99 |
114
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
100 for k in sorted(self.children.keys()): |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
101 sub.extend(self.children.get(k).getSubtreeAsListDepthFirst()) |
105
246d87d33f25
CLOSED - # 79: sortierung der liste der projekte pro abteilung
casties
parents:
97
diff
changeset
|
102 |
114
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
103 return sub |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
104 |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
105 |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
106 def getSubtreeAsListBreadthFirst(self): |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
107 """Return the subtree as flattened list, breadth first, sorted by key.""" |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
108 q = [self] |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
109 sub = [] |
115 | 110 while len(q) > 0: |
114
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
111 node = q.pop(0) |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
112 if node.value is not None: |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
113 sub.extend(node.getValue(asList=True)) |
27 | 114 |
114
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
115 if node.children is not None: |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
116 clist = sorted(node.children.values(), key=lambda x:x.key) |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
117 q.extend(clist) |
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
118 |
105
246d87d33f25
CLOSED - # 79: sortierung der liste der projekte pro abteilung
casties
parents:
97
diff
changeset
|
119 return sub |
27 | 120 |
121 | |
122 def getSubtreeAsText(self): | |
114
1acfcaaa5ca3
fixed HashTree.getSubTreeAsList when using breadth first.
casties
parents:
105
diff
changeset
|
123 """Return whole tree as text. Depth first.""" |
27 | 124 if self.children is None: |
125 return "(%s:%s)"%(self.key, self.value) | |
126 else: | |
127 sub = "(%s:%s):["%(self.key, self.value) | |
43 | 128 for k in sorted(self.children.keys()): |
27 | 129 sub += self.children.get(k).getSubtreeAsText() |
130 sub += ", " | |
131 | |
132 return sub + "] " | |
133 | |
134 | |
135 class HashTree: | |
136 """Tree using dictionaries""" | |
137 | |
43 | 138 # root HashTreeNode |
27 | 139 root = None |
43 | 140 # separator by which key strings are split into parts |
27 | 141 keySeparator = '.' |
43 | 142 # function applied to key parts |
27 | 143 keyFn = None |
144 | |
145 def __init__(self, keySeparator='.', keyFn=None): | |
52 | 146 """Create a HashTree. |
43 | 147 |
148 @param keySeparator string by which key strings are split into parts | |
149 @param keyFn function applied to key parts (e.g. int if key parts are numbers) | |
150 """ | |
27 | 151 self.root = HashTreeNode() |
152 self.keySeparator = keySeparator | |
153 self.keyFn = keyFn | |
154 | |
155 | |
39 | 156 def _splitkey(self, key): |
52 | 157 """Return a list of key parts""" |
39 | 158 if isinstance(key, basestring): |
159 # its a string - split | |
160 keys = key.split(self.keySeparator) | |
161 if self.keyFn is not None: | |
162 keys = [self.keyFn(k) for k in keys] | |
43 | 163 |
39 | 164 elif isinstance(key, list): |
165 # its a list - keep | |
166 keys = key | |
43 | 167 |
39 | 168 else: |
169 # not a list - wrap in list | |
170 keys = [key] | |
171 | |
172 return keys | |
173 | |
174 | |
27 | 175 def getNode(self, key): |
52 | 176 """Return node under key from the tree. |
177 | |
27 | 178 key can be sequence of key string or a single string using keySeparator. |
30 | 179 If key is None, returns root node. |
27 | 180 """ |
30 | 181 if key is None: |
182 return self.root | |
183 | |
39 | 184 keys = self._splitkey(key) |
27 | 185 |
186 node = self.root | |
187 for k in keys: | |
188 node = node.getNode(k) | |
189 if node is None: | |
190 return None | |
191 | |
192 return node | |
193 | |
194 | |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
195 def get(self, key, onlyFirst=True): |
52 | 196 """Return value under key from the tree. |
197 | |
27 | 198 key can be sequence of key string or a single string using keySeparator. |
199 """ | |
200 node = self.getNode(key) | |
201 if node is None: | |
202 return None | |
203 | |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
204 return node.getValue(onlyFirst=onlyFirst) |
27 | 205 |
206 | |
207 def add(self, key, value): | |
52 | 208 """Add value under key to the tree. |
209 | |
27 | 210 key can be sequence of key string or a single string using keySeparator. |
211 """ | |
39 | 212 keys = self._splitkey(key) |
27 | 213 node = self.root |
257 | 214 #logging.debug("hashtree.add: keys=%s value=%s"%(repr(keys), repr(value))) |
27 | 215 for k in keys: |
216 nextnode = node.getNode(k) | |
217 if nextnode is None: | |
218 nextnode = HashTreeNode(key=k) | |
219 node.addNode(nextnode) | |
220 | |
221 node = nextnode | |
222 | |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
223 node.setValue(value) |
39 | 224 |
27 | 225 |
39 | 226 def getChildrenOf(self, key): |
52 | 227 """Return the list of child (values) of the node under key.""" |
39 | 228 node = self.getNode(key) |
97 | 229 if getattr(node, 'children', None) is None: |
39 | 230 return [] |
231 else: | |
43 | 232 # sort children by key |
233 childlist = sorted(node.children.items(), key=lambda x:x[0]) | |
234 # and return the values | |
228
afc96bc56817
also show multiple projects with the same number (including none) in the tree.
casties
parents:
115
diff
changeset
|
235 return [n.getValue() for k, n in childlist if n.value is not None] |
39 | 236 |
237 | |
238 def getAncestorsOf(self, key): | |
52 | 239 """Return the list of ancestor (values) of the node under key. |
240 | |
241 Order: root element first.""" | |
39 | 242 keys = self._splitkey(key) |
243 node = self.root | |
244 ancestors = [] | |
245 for k in keys: | |
246 if node.value is not None: | |
247 ancestors.append(node.value) | |
248 | |
249 node = node.getNode(k) | |
250 if node is None: | |
251 return ancestors | |
252 | |
253 return ancestors | |
254 | |
27 | 255 |