The Unfun Cat
The Unfun Cat

Reputation: 31908

Double-indexed dictionary

I want to be able to store and look up values in a dictionary based on two integer values.

So when I look up a value I want to use the keys read_length and min_size to access the element, like so:

number_of_read_lengths[read_length][min_size]

I know I can create nested dictionaries, but that is a slight hassle.

Is there a simple way of doing what I want to do?

Upvotes: 27

Views: 39806

Answers (5)

Johanna Larsson
Johanna Larsson

Reputation: 10761

You can use any immutable and hashable object as key, including tuples

number_of_read_lengths = {}    
number_of_read_lengths[14,3] = "Your value"

Upvotes: 44

Ehsan Ab
Ehsan Ab

Reputation: 679

Here is another way to define double indexed dictionaries. For me it is easier to visualize this one rather than other methods.

dict_dict_v2 = {}
dict_dict_v2.setdefault(2, {})
dict_dict_v2.setdefault(3, {})
dict_dict_v2[2]['1.1.1.1'] = {}
dict_dict_v2[2]['1.0.1.0'] = {}
dict_dict_v2[3]['1.1.1.1'] = "double"
dict_dict_v2[3]['1.0.1.0'] = 12    

dict_dict_v2[2]['1.1.1.1']['mac']=1111
dict_dict_v2[2]['1.1.1.1']['id']=1111

dict_dict_v2[2]['1.0.1.0']['id']=1010

print str(dict_dict_v2)
"""output: 
{1: {'1.0.0.0': {'mac': 1010, 'id': 1000}, '1.1.1.1': {'mac': 1111}}, 
 2: {'1.1.1.1': {'mac': 1111, 'id': 1111}, '1.0.1.0': {'id': 1010}}, 
 3: {'1.1.1.1': 'double', '1.0.1.0': 12}}
"""

You could use the dict basic functions as below:

print "len-> "+str(len(dict_dict_v2[2]))
print "keys-> "+str(dict_dict_v2[2].keys())
print "values-> "+str(dict_dict_v2[2].values())
"""output: 
len-> 2
keys-> ['1.1.1.1', '1.0.1.0']
values-> [{'mac': 1111, 'id': 1111}, {'id': 1010}]
"""
print "len for 1.1.1.1-> "+str(len(dict_dict_v2[2]['1.1.1.1']))
print "keys for 1.1.1.1-> "+str(dict_dict_v2[2]['1.1.1.1'].keys())
print "values for 1.1.1.1-> "+str(dict_dict_v2[2]['1.1.1.1'].values())
"""output: 
len for 1.1.1.1-> 2
keys for 1.1.1.1-> ['mac', 'id']
values for 1.1.1.1-> [1111, 1111]
"""

Upvotes: 0

pawroman
pawroman

Reputation: 1300

Using tuples could be quite annoying -- you got to remember to place the tuple during indexing.

I would recommend a nested dict, but a defaultdict, like so:

from collections import defaultdict

number_of_read_lengths = defaultdict(dict)

number_of_read_lengths[1][2] = 3

print(number_of_read_lengths)

This code would give:

defaultdict(<type 'dict'>, {1: {2: 3}})

This way, any non-existing element in the number_of_read_lengths dict will be created as a dict when accessing or setting it. Simple and effective.

More info on defaultdict: http://docs.python.org/library/collections.html#collections.defaultdict There are also examples: http://docs.python.org/library/collections.html#defaultdict-examples

Upvotes: 4

K Z
K Z

Reputation: 30453

Just to expand a bit more from the comment I made:

A dict key must be hashable, which a simple tuple is. However, a tuple that contains unhashable values such as lists, is not hashable (even though it is immutable!) and therefore cannot be used as dict key:

>>> bad = ([12],[32])
# still immutable
>>> bad[1] = [21]
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

# but not hashable!
>>> d = {}
>>> d[bad] = 2
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: unhashable type: 'list'

You can even have mutable and hashable objects as dict keys, but it's not really useful and should be avoided.

Upvotes: 3

Pierre GM
Pierre GM

Reputation: 20339

You could try to use tuples as keys:

number_of_read_lengths[(read_length, min_size)]

Upvotes: 3

Related Questions