updated __setitem__ to allow for update items using multiple keys

This commit is contained in:
Lukasz Forynski 2013-09-01 01:38:30 +01:00
parent d27da38aa7
commit 045d3cc5ca
2 changed files with 68 additions and 10 deletions

View File

@ -2,14 +2,33 @@ multi_key_dict
======================
Implementation of a multi-key dictionary.
Implementation of a multi-key dictionary, i.e.:
This kind of dictionary has a similar interface to the standard dictionary,
(key1[,key2, ..]) => value
and indeed if used with single key key elements - it's behaviour is the same as for a standard dict.
This dictionary has a similar interface to the standard dictionary => but is extended to support multiple keys referring to the same element.
If element is created using multiple keys, e.g.:
.. code:: python
from multi_key_dict import multi_key_dict
k = multi_key_dict()
k[1000, 'kilo', 'k'] = 'kilo (x1000)'
print k[1000] # will print 'kilo (x1000)'
print k['k'] # will also print 'kilo (x1000)'
# the same way objects can be updated, deleted:
# and if an object is updated using one key, the new value will
# be accessible using any other key, e.g. for example above:
k['kilo'] = 'kilo'
print k[1000] # will now print 'kilo' as value was updated
These elements can be accessed using either of those keys (e.g for read/update/deletion).
However it also allows for creation of elements using multiple keys (using tuples/lists). Such elements can be accessed using either of those keys (e.g for read/update/deletion).
Multi-key dict provides also extended interface for iterating over items and keys (e.g. by the key type), which might be useful when creating, e.g. dictionaries with index-name key pair allowing to iterate over items using either: names or indexes.
It can be useful for many many other similar use-cases, and there is no limit to the number of keys used to map to the value.
There are also methods to get other keys that map to the same element and others. Refer to examples and test code to see it in action.
There are few other useful methods, e.g. to iterate over dictionary (by/using) selected key type, finding other keys mapping to the same value etc. Refer to example/test code to see it in action.

View File

@ -50,7 +50,7 @@ class multi_key_dict(object):
# below creates entry with two possible key types: int and str,
# mapping all keys to the assigned value
k[1000, 'kilo', 'k'] = 'kilo (x1000)'
print k[100] # will print 'kilo (x1000)'
print k[1000] # will print 'kilo (x1000)'
print k['k'] # will also print 'kilo (x1000)'
# the same way objects can be updated, and if an object is updated using one key, the new value will
@ -67,12 +67,32 @@ class multi_key_dict(object):
def __setitem__(self, keys, value):
""" Set the value at index (or list of indexes) specified as keys.
Note, that if multiple key list is specified - none of them can exist already
in this dictionary. If it does exist, KeyError is raised. """
if(type(keys) in [tuple, list]):
Note, that if multiple key list is specified, either:
- none of keys should map to an existing item already (item creation), or
- all of keys should map to exactly the same item (as previously created)
(item update)
If this is not the case - KeyError is raised. """
if(type(keys) in [tuple, list]):
num_of_keys_we_have = reduce(lambda x, y: x+y, map(lambda x : self.has_key(x), keys))
if num_of_keys_we_have:
raise KeyError(', '.join(str(key) for key in keys))
all_select_same_item = True
for key in keys:
direct_key = None
try:
if direct_key is None:
direct_key = self.items_dict[key]
else:
new = self.items_dict[key]
if new != direct_key:
all_select_same_item = False
break
except:
all_select_same_item = False
break;
if num_of_keys_we_have < len(keys) and not all_select_same_item:
raise KeyError(', '.join(str(key) for key in keys))
first_key = keys[0] # combination if keys is allowed, simply use the first one
else:
first_key = keys
@ -456,6 +476,25 @@ def test_multi_key_dict():
# test keys()
assert (m.keys(int) == tst_range), 'm.keys(int) is not as expected.'
# test setitem with multiple keys
m['xy', 999, 'abcd'] = 'teststr'
try:
m['xy', 998] = 'otherstr'
assert(False), 'creating / updating m[\'xy\', 998] should fail!'
except KeyError, err:
pass
m['xy', 999] = 'otherstr'
assert (m['xy'] == 'otherstr'), 'm[\'xy\'] is not as expected.'
assert (m[999] == 'otherstr'), 'm[999] is not as expected.'
assert (m['abcd'] == 'otherstr'), 'm[\'abcd\'] is not as expected.'
m['abcd', 'xy'] = 'another'
assert (m['xy'] == 'another'), 'm[\'xy\'] is not == \'another\'.'
assert (m[999] == 'another'), 'm[999] is not == \'another\''
assert (m['abcd'] == 'another'), 'm[\'abcd\'] is not == \'another\'.'
print 'All test passed OK!'