Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have a dictionary with same-name keys?

I need to have a dictionary which might have same names for some keys and return a list of values when referencing the key in that case.

For example

print mydict['key']
[1,2,3,4,5,6]
like image 514
b9107007 Avatar asked Jul 25 '11 08:07

b9107007


People also ask

Can a dictionary have same keys?

First, a given key can appear in a dictionary only once. Duplicate keys are not allowed. A dictionary maps each key to a corresponding value, so it doesn't make sense to map a particular key more than once.

Can dictionaries have repeated keys?

Because you cannot have duplicate keys in a dictionary. It does iterate from 0 to 9, but each time it overwrites the previous value for the key named 'key' . Since 9 is the last value written, it is the only value assigned to 'key' .

Can dictionary have duplicates?

The Key value of a Dictionary is unique and doesn't let you add a duplicate key entry.

Are duplicates allowed in dictionary python?

Python dictionary doesn't allow key to be repeated.


4 Answers

For consistency, you should have the dictionary map keys to lists (or sets) of values, of which some can be empty. There is a nice idiom for this:

from collections import defaultdict
d = defaultdict(set)

d["key"].add(...)

(A defaultdict is like a normal dictionary, but if a key is missing it will call the argument you passed in when you instantiated it and use the result as the default value. So this will automatically create an empty set of values if you ask for a key which isn't already present.)


If you need the object to look more like a dictionary (i.e. to set a value by d["key"] = ...) you can do the following. But this is probably a bad idea, because it goes against the normal Python syntax, and is likely to come back and bite you later. Especially if someone else has to maintain your code.

class Multidict(defaultdict):
    def __init__(self):
        super(Multidict, self).__init__(set)

    def __setitem__(self, key, value):
        if isinstance(value, (self.default_factory)): # self.default_factory is `set`
            super().__setitem__(key, value)
        else:
            self[key].append(value)

I haven't tested this.

like image 119
Katriel Avatar answered Oct 03 '22 09:10

Katriel


You can also try paste.util.multidict.MultiDict

$ easy_install Paste

Then:

from paste.util.multidict import MultiDict
d = MultiDict()
d.add('a', 1)
d.add('a', 2)
d.add('b', 3)
d.mixed()
>>> {'a': [1, 2], 'b': 3}
d.getall('a')
>>> [1, 2]
d.getall('b')
>>> [3]

Web frameworks like Pylons are using this library to handle HTTP query string/post data, which can have same-name keys.

like image 37
sayap Avatar answered Oct 03 '22 08:10

sayap


You can use:

myDict = {'key': []}

Then during runtime:

if newKey in myDict:
    myDict[newKey].append(value)
else:
    myDict[newKey] = [value]

Edited as per @Ben's comment:

myDict = {}
myDict.setdefault(newKey, []).append(value)
like image 32
Artsiom Rudzenka Avatar answered Oct 03 '22 08:10

Artsiom Rudzenka


This is an ideal place to use a defaultdict object from the collections library

from collections import defaultdict

mydict = defaultdict(set)
mydict['key'] += set([1,2,3,4])
mydict['key'] += set([4,5,6])

print(mydict['key'])

returns [1,2,3,4,5,6]

In the case where a key is referenced that has not been implicitly assigned, an empty set is returned.

print(mydict['bad_key'])

returns []

Using setdefault on a dict from the standard library would require a significant change in your syntax when assigning values and can get rather messy. I've never used Multidict, but it also looks like a significant change in the way assignments are made. Using this method, you simply assume that there may already be a value associated with this key in the dictionary and slightly modify your assignment operator by using the '+=' operator when assigning key values.

FYI - I am a big fan of using the NoneType as the default which results in any access of an invalid key returning None. This behaves properly in most cases including iterating and json dumps, but for your specific need the default should be of type set unless you want to enable having duplicate values stored in the key. Then use a list. In fact, anytime you have a homogenous dictionary the default should be of that type.

mydict = defaultdict(lambda: None)
like image 25
Zane Westover Avatar answered Oct 03 '22 10:10

Zane Westover