view HashTree.py @ 43:196db636a8fd

fixed sorting of project lists.
author casties
date Sun, 28 Apr 2013 14:17:32 +0200
parents bbad6a092861
children 1ed79b33200c
line wrap: on
line source

import logging
    
class HashTreeNode:
    """Node of a HashTree.
    Has a value and keeps children in a dict indexed by key."""
    key = None
    value = None
    children = None
    
    def __init__(self, key=None, value=None, children=None):
        """create node"""
        self.key = key
        self.value = value
        self.children = children


    def getNode(self, key):
        """return node under key"""
        if self.children is None:
            return None
        else:
            return self.children.get(key, None)


    def addNode(self, node):
        """add child node using key from node"""
        if self.children is None:
            self.children = {node.key : node}
        else:
            self.children[node.key] = node
            

    def getSubtreeAsList(self):
        """returns the subtree as flattened list sorted by key (depth first)"""
        if self.children is None:
            if self.value is None:
                return []
            else:
                return [self.value]
            
        else:
            if self.value is None:
                sub = []
            else:
                sub = [self.value]
                
            for k in sorted(self.children.keys()):
                sub.extend(self.children.get(k).getSubtreeAsList())
                
            return sub


    def getSubtreeAsText(self):
        """prints whole tree as text"""
        if self.children is None:
            return "(%s:%s)"%(self.key, self.value)
        else:
            sub = "(%s:%s):["%(self.key, self.value)
            for k in sorted(self.children.keys()):
                sub += self.children.get(k).getSubtreeAsText()
                sub += ", "
                
            return sub + "] "

    


class HashTree:
    """Tree using dictionaries"""
    
    # root HashTreeNode
    root = None
    # separator by which key strings are split into parts
    keySeparator = '.'
    # function applied to key parts
    keyFn = None
    
    def __init__(self, keySeparator='.', keyFn=None):
        """creates a HashTree.
        
        @param keySeparator string by which key strings are split into parts
        @param keyFn function applied to key parts (e.g. int if key parts are numbers)
        """
        self.root = HashTreeNode()
        self.keySeparator = keySeparator
        self.keyFn = keyFn
    

    def _splitkey(self, key):
        """returns a list of key parts"""
        if isinstance(key, basestring):
            # its a string - split
            keys = key.split(self.keySeparator)
            if self.keyFn is not None:
                keys = [self.keyFn(k) for k in keys]
                
        elif isinstance(key, list):
            # its a list - keep
            keys = key
            
        else:
            # not a list - wrap in list
            keys = [key]
            
        return keys


    def getNode(self, key):
        """gets node under key from the tree.
        key can be sequence of key string or a single string using keySeparator.
        If key is None, returns root node.
        """
        if key is None:
            return self.root

        keys = self._splitkey(key)
            
        node = self.root
        for k in keys:
            node = node.getNode(k)
            if node is None:
                return None
            
        return node


    def get(self, key):
        """gets value under key from the tree.
        key can be sequence of key string or a single string using keySeparator.
        """
        node = self.getNode(key)
        if node is None:
            return None
        
        return node.value

     
    def add(self, key, value):
        """adds value under key to the tree.
        key can be sequence of key string or a single string using keySeparator.
        """
        keys = self._splitkey(key)
        node = self.root
        for k in keys:
            nextnode = node.getNode(k)
            if nextnode is None:
                nextnode = HashTreeNode(key=k)
                node.addNode(nextnode)
            
            node = nextnode
            
        node.value = value

        
    def getChildrenOf(self, key):
        """returns the list of child (values) of the node under key."""
        node = self.getNode(key)
        if node.children is None:
            return []
        else:
            # sort children by key
            childlist = sorted(node.children.items(), key=lambda x:x[0])
            # and return the values
            return [n.value for (k, n) in childlist if n.value is not None]


    def getAncestorsOf(self, key):
        """returns the list of ancestor (values) of the node under key.
        ordered from root up."""
        keys = self._splitkey(key)
        node = self.root
        ancestors = []
        for k in keys:
            if node.value is not None:
                ancestors.append(node.value)
                
            node = node.getNode(k)
            if node is None:
                return ancestors
            
        return ancestors