Is it possible to assign the same value to multiple keys in a dict object at once?

PythonSyntaxDictionary

Python Problem Overview


In Python, I need a dictionary object which looks like:

{'a': 10, 'b': 20, 'c': 10, 'd': 10, 'e': 20}

I've been able to get this successfully by combining the dict.update() and dict.fromkeys() functions like so:

myDict = {}
myDict.update(dict.fromkeys(['a', 'c', 'd'], 10))
myDict.update(dict.fromkeys(['b', 'e'], 20))

However, because the code is being written for novice users who may need to make add keys/values on occasion, I'd prefer a simple bare-bones (Perl-like) syntax such as:

myDict = {}
myDict['a', 'c', 'd'] = 10
myDict['b', 'e'] = 20

This, however, gives me:

myDict = {('a', 'c', 'd'): 10, ('b', 'e'): 20}

Is there a way I can simplify my first example (using dict.update() and dict.fromkeys()) further, and get the dict object I'm looking for?

Or, alternatively, if I have a dict with tuples as in my second example, is there an easy way for me to do a lookup such as myDict['c'] or myDict.get('c') and get the value 10?

Python Solutions


Solution 1 - Python

I would say what you have is very simple, you could slightly improve it to be:

my_dict = dict.fromkeys(['a', 'c', 'd'], 10)
my_dict.update(dict.fromkeys(['b', 'e'], 20))

If your keys are tuple you could do:

>>> my_dict = {('a', 'c', 'd'): 10, ('b', 'e'): 20}
>>> next(v for k, v in my_dict.items() if 'c' in k)      # use .iteritems() python-2.x
10

This is, of course, will return first encountered value, key for which contains given element.

Solution 2 - Python

Similar to @SilentGhost but a more declarative syntax (with Python 3.5+) I prefer:

myDict = {
  **dict.fromkeys(['a', 'c', 'd'], 10), 
  **dict.fromkeys(['b', 'e'], 20)
}

Solution 3 - Python

Your first example can be simplified using a loop:

myDict = {}
for key in ['a', 'c', 'd']:
    myDict[key] = 10
for key in ['b', 'e']:
    myDict[key] = 20

No specialized syntax or trickery, and I can't think of anything which would be easier to understand.

Regarding your second question, there is no simple and efficient way to do the lookup as in your second example. I can only think of iterating over the keys (tuples) and checking whether the key is in any of them, which isn't what you're looking for. Stick to using a straightforward dict with the keys you want.

In general, if you are aiming for code that can be understood by novices, stick to the basics such as if conditions and for/while loops.

Solution 4 - Python

You could inherit from dict to implement a sort of "update from keys":

class LazyDict(dict):
    def keylist(self, keys, value):
        for key in keys:
            self[key] = value

>>> d = LazyDict()
>>> d.keylist(('a', 'b', 'c'), 10)
>>> d
{'a': 10, 'c': 10, 'b': 10}

but I prefer loop solution

Solution 5 - Python

Dict union (3.9+)

Now with Python 3.9, you can do this:

myDict = dict.fromkeys(['a', 'c', 'd'], 10) | dict.fromkeys(['b', 'e'], 20)

Although personally, I'm not sure I would use this, since it's hard to read.

Dict comprehension

myDict = {
    k: v
    for keys, v in [(['a', 'c', 'd'], 10), (['b', 'e'], 20)]
    for k in keys
    }

This is also hard to read, but I'm mentioning it for the sake of completeness.

reference

Solution 6 - Python

Method:

def multi_key_dict_get(d, k):
    for keys, v in d.items():
        if k in keys:
            return v
    return None

Usage:

my_dict = {
   ('a', 'b', 'c'): 10,
   ('p', 'q', 'r'): 50
}

value = multi_key_dict_get(my_dict, 'a')

Solution 7 - Python

While @SilentGhost's answer works pretty fine with single length of keys, it won't work correctly for those looking for a "multiple character length of keys" solution, and so I've thought of the below solution [...]

let's say that we have the above dict and keys we are looking for:

my_dict = {
    'key1':'KEY_1',
    ('tk1', 'tk2','tk3'):'TK_1_2_3',
    'key2':'KEY_2'
}
my_keys = ['key2','ke', 'tk2','k','key','exception'] # key's I'm looking for

the example & SOLUTION below:

for key in my_keys:
    print(next((v for k, v in my_dict.items() if (key == k) or (isinstance(k,tuple) and key in k)),None))

CORRECTLY outputs:

KEY_2
None
TK_1_2_3
None
None
None

While with (a slightly modified solution [so it won't throw StopIteration exception] of) @SilentGhost's answer

for key in my_keys:
    print(next((v for k, v in my_dict.items() if key in k),None)) # added ((...),None)

the results are WRONG because [...]2 if not a StopIteration exception:

KEY_2
KEY_1
TK_1_2_3
KEY_1
KEY_1
None

While personally I wouldn't really recommend it from a perspective of speed efficiency (at least not for all use cases), it is indeed a way of solving this issue and so I decided to post it.

Solution 8 - Python

There is one way that comes to mind. Still has the limitation of only having the same contents.

The value of one key can't change another.

key_map = {
    'KEY_UP': move_up,
    'w': 'KEY_UP',
}
  
for key in key_map:
    # loop over the dict
    
    if key_map[key] in key_map:
        # one key is the value of the other
        
        target_key = key_map[key]
        key_map[key] = key_map[target_key]
        # overwrite key white the contents of the other

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBillyBBoneView Question on Stackoverflow
Solution 1 - PythonSilentGhostView Answer on Stackoverflow
Solution 2 - Pythonshao.loView Answer on Stackoverflow
Solution 3 - PythontaleinatView Answer on Stackoverflow
Solution 4 - PythonremosuView Answer on Stackoverflow
Solution 5 - PythonwjandreaView Answer on Stackoverflow
Solution 6 - PythonShameemView Answer on Stackoverflow
Solution 7 - PythonGiorgos XouView Answer on Stackoverflow
Solution 8 - Pythontinker ponyView Answer on Stackoverflow