Access a dictionary as a list
I have a data source which is best modeled with a dictionary (it is a collection of key=value pairs). For a specific visualization purpose, I ne开发者_JS百科ed to provide a list-like data access interface (in addition to the regular dictionary interface), meaning that you should be able to do the following:
data["mykey"] # returns the associated value
data[12][0] # returns the 13th key in the dictionary
data[12][1] # returns the 13th value in the dictionary
I cannot find an appropriate facade implementation - if I store the indices as the dictionary key:
data[12] = ("mykey", "myval")
I can easily solve the last two cases, but I loose the ability to do the first. If I store data like
data["mykey"] = "myval"
I have to enumerate all keys and values in a temporary list before I can return elements.
Notice that all this implementations assume I am using an OrderedDict
.
How would you provide both interfaces?
If you are curious, this is for creating a PyQt QAbstractTableModel
where the underlying data container is a dictionary.
Thanks.
I have to do the same thing to represent data in a ListCtrl that needs to be accessible by a key rather than by index at times (so that it does not have to be searched if I get an arbitrary value to locate). If you have a list of dictionaries, the best I found was to create another dictionary with references to the same items, but accessible by key. This becomes my data load in method:
def SetData(self, cols, data):
for idx, row in enumerate(data):
item = dict((k, v.rstrip() if hasattr(v, 'rstrip') else v) for k, v in zip(cols, row))
self.data[idx] = item
self.byid[row[0]] = item
So I have a list of dictionaries accessible in self.data, and then another dictionary in self.byid that keeps the same items, but by the id column (column 0 in my rows in this case). When I need to update, as long as I get an ID, I can call self.byid[id][field] = newval
. Because everything in Python is a pointer (reference), changing the value of the dictionary stored in self.byid is reflected in the list of dictionaries stored in self.data. Works like a charm.
list(data.items())[12]
will return a (key, value)
tuple for the 13th key-value pair in your OrderedDict
. list(data.keys())[12]
will return the 13th key on its own, and list(data.values())[12]
will return the 13th value.
This probably isn't a good idea for large dict
s, though, due to the list being recreated each time.
(However, it's the very same method used by OrderedDict
in its __repr__
method: return '%s(%r)' % (self.__class__.__name__, list(self.items()))
)
Take your dict{} and create another one where the keys are indicies and the values are either the keys to the original dict, or a tuple/list from the original dict.
d = {"key1":"value1","key2":"value2","key3":"value3"}
d2 = {1:"key1",2:"key2",3:"key3"}
Then:
d[d2[3]]
returns
'value3'
Or defining d2 using the following:
d2 = {1:["key1","value1"],2:["key2","value2"],3:["key3","value3"]}
Gets you the access you wanted using d2[3][0] and d2[3][1] for the key and value respectively.
A dict
subclass that attempts index-based access of keys but fails over to default key access might do the job. Something along the lines of:
from collections import OrderedDict
class IndexableDict(OrderedDict):
def __getitem__(self, key):
"""Attempt to return based on index, else try key"""
try:
_key = self.keys()[key]
return (_key, super(IndexableDict, self).__getitem__(_key))
except (IndexError, TypeError):
return super(IndexableDict, self).__getitem__(key)
d = IndexableDict(spam='eggs', messiah=False)
d['messiah'] ## False
d[1] ## ('messiah', False)
d[0] ## ('spam', 'eggs')
EDIT: This will break if you use integers as keys.
精彩评论