Package: nodetrie
NodeTrieA Trie data structure library.Installationpip install nodetrieMotivation, design goalsNodeTrie is a Python extension to a native C library written for this purpose.It came about from a lack of viable alternatives for Python. While other trie library implementations exist, they suffer from severe limitations such asRead only structures, no insertionsHigh memory use for large treesLack of searching, particularly file mask or wild card style searchingSlow insertsExisting implementations on PyPi fall into these broad categories, includingMarissa-Trie(read only) anddatrie(slow inserts, very high memory use for large trees).NodeTrie’s C library is designed to minimize memory use as much as possible and still allow arbitrary length trees that can be searched.Each node has a name associated with it as its data, along with children list and number of children.Features and design notesNodeTrie is an n-ary tree, meaning any one node can have any number of childrenNode children arrays are dynamically resizedas needed on insertionon a per node basis. No fixed minimum nor maximum sizeNode names can be of arbitrary length, available memory allowingNode names fromNode.nameare always unicode in either Python 2/3Any python string type may be used on insertionNode names are implicitly decoded from unicode on insertion, if needed, withnodetrie.ENCODING(utf-8) default encoding which can be overriddenNew PythonNodeobjects are created from the underlying C pointers every timeNode.childrenis called. There is overhead on the Python interpreter to create these objects. It is safe and better performing to keep and re-use children references instead, see examples belowLimitationsDeletions are not implementedThe C library implementation uses pointer arrays for children to reduce search space complexity and character pointers for names to allow for arbitrary name lengths. This may lead to memory fragmentationNodeobjects in python are read only. It is not possible to override the name of an existingNodeobject nor modify its attributesCharacter encodings that allow for null characters such as UCS-2should not be usedExample UsagefromnodetrieimportNode# This is the root of the tree, keep a reference to it.# Deleting or letting the root node go out of scope will de-allocate# the entire treenode=Node()# Insert a linked tree so that a->b->c->d where -> means 'has child node'node.insert_split_path(['a','b','c','d'])node.children[0].name=='a'# Sub-trees can be referred to by child nodesa_node=node.children[0]a_node.name=='a'a_node.children[0].name=='b'a_node.is_leaf()==False# Insertions create only new nodes# Insert linked tree so that a->b->c->ddnode.insert_split_path(['a','b','c','dd'])# Only one 'a' nodenode.children_size==1# Existing references to nodes will have correct children# after insertion without recreating the node object.# Here, a_node is an existing object prior to more nodes# being added to its sub-tree. After insertion, a's sub-tree contains newly# inserted nodes as expected# 'c' node is first child of 'b' which is first child of 'a'# 'c' node has two children, 'd' and 'dd'c_node=a_node.children[0].children[0]c_node.children_size==2c_node.is_leaf()==False# 'd' and 'dd' are both leaf nodesleaf_nodes=[cforcinc_node.childrenifc.is_leaf()]len(leaf_nodes)==2NoteDe-allocationTree is de-allocated when and only when root node goes out of scope or is deleted. Letting sub-tree objects go out of scope or explicitly deleting them willnot de-allocate that sub-tree.NoteSub-tree insertionsInsertions on non-root nodes work as expected. However,Node.insertdoesnotcheck if a node is already present, unlikeNode.insert_split_pathSearchingNodeTrie supports exact name as well as file mask matching tree search.from__future__importprint_functionfromnodetrieimportNodenode=Node()forpathsin[['a','b','c1','d1'],['a','b','c1','d2'],['a','b','c2','d1'],['a','b','c2','d2']]:node.insert_split_path(paths)forpath,_nodeinnode.search(node,['a','b','*','*'],[]):print(path,_node)Output[u'a',u'b',u'c1',u'd1']Node:'d1'[u'a',u'b',u'c1',u'd2']Node:'d2'[u'a',u'b',u'c2',u'd1']Node:'d1'[u'a',u'b',u'c2',u'd2']Node:'d2'Separator joined node names for a matched sub-tree are returned by the query function.formatchinnode.query('a.b.*.*'):print(match)formatchinnode.query('a|b|*|*',separator='|'):print(match)Output(u'a.b.c1.d1',Node:'d1')(u'a.b.c1.d2',Node:'d2')(u'a.b.c2.d1',Node:'d1')(u'a.b.c2.d2',Node:'d2')(u'a|b|c1|d1',Node:'d1')(u'a|b|c1|d2',Node:'d2')(u'a|b|c2|d1',Node:'d1')(u'a|b|c2|d2',Node:'d2')Contributions are most welcome.