Created
October 17, 2011 13:00
-
-
Save aramk/1292554 to your computer and use it in GitHub Desktop.
Python Ordered Dictinary
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
''' | |
Ordered dict | |
http://ak.net84.net/projects/python-ordered-dictionary/ | |
Example usage: | |
>>> o = Ordict( ('abc', 123), ('def', '456', 3) ) | |
>>> o['ghi'] = '789' | |
>>> o['jkl'] = 987 | |
>>> o['mno'] = '654' # replaces index 3 | |
>>> o.set('pqr', 321, 5) | |
>>> print o | |
Ordict {0: ['abc', 123], 1: ['ghi', '789'], 2: ['jkl', 987], 3: ['mno', '654'], 5: ['pqr', 321]} | |
>>> print o.item_at(2) | |
['jkl', 987] | |
''' | |
class Ordict(dict): | |
def __init__(self, *args, **kwargs): | |
self.ordered_items = {} # {0:('a':'b'), 4:('c','d')...} | |
self.item_to_order = {} # {'a':0, 'c':4} | |
self.next_index = 0 # The next available index | |
for item in args: | |
if len(item) > 3: | |
raise Exception('Ordered items must be tuples: (key , value [, index])') | |
elif len(item) == 2: | |
self.__setitem__(item[0], item[1]) | |
elif len(item) == 3: | |
if item[2] < 0: | |
raise Exception('Index must be given as a positive integer') | |
self.__setitem__(item[0], item[1], item[2]) | |
return dict.__init__(self, **kwargs) | |
def __getitem__(self, key): | |
return dict.__getitem__(self, str(key)) | |
def __setitem__(self, key, value, index=None): | |
key = str(key) | |
_index = self.next_index | |
if type(index) is int: | |
_index = abs(index) | |
# Find next available index. If current next_index is untaken, keep it. | |
# If this set took it, increment | |
if _index == self.next_index: | |
self.next_index += 1 | |
else: | |
self.next_index += 1 # increment index | |
self.ordered_items[_index] = [key, value] | |
self.item_to_order[key] = _index | |
dict.__setitem__(self, key, value) | |
def __delitem__(self, key): | |
key = str(key) | |
index = self.item_to_order[key] | |
del self.ordered_items[index] | |
return dict.__delitem__(self, key) | |
def __iter__(self): | |
for index in self.ordered_items: | |
item = self.ordered_items[index] | |
yield item[0] | |
def __repr__(self): | |
return 'Ordict ' + self.ordered_items.__repr__() | |
def set(self, key, value, index=None): | |
''' | |
Set the key:value with optional index | |
''' | |
return self.__setitem__(key, value, index) | |
def index_of(self, key, default=None): | |
''' | |
Return index of key or 'default' if it doesn't exist | |
''' | |
key = str(key) | |
return self.item_to_order[key] if key in self.item_to_order else default | |
def item_at(self, index, default=None): | |
''' | |
Return item at index as a tuple or 'default' if it doesn't exist | |
''' | |
index = int(index) | |
item = self.ordered_items[index] if index in self.ordered_items else None | |
if item: | |
return item | |
else: | |
return default | |
def key_at(self, index, default=None): | |
''' | |
Return key at index or 'default' if it doesn't exist | |
''' | |
index = int(index) | |
item = self.item_at(index) | |
if item: | |
return item[0] | |
else: | |
return default | |
def value_at(self, index, default=None): | |
''' | |
Return value at index or 'default' if it doesn't exist | |
''' | |
index = int(index) | |
item = self.item_at(index) | |
if item: | |
return item[1] | |
else: | |
return default |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment