Multiple assignments into a python dictionary

PythonDictionary

Python Problem Overview


Is it possible to assign values to more than one keys of a dictionary in a more concise way than the one below?

I mean, let d be a dictionary initialized as below:

d={'a':1,'b':2,'c':3}

To assign values to multiple keys I need to do this:

d['a']=10
d['b']=200
d['c']=30

Can I achieve same with something like this:

d['a','b','c']=10,200,30

Thanks.

Python Solutions


Solution 1 - Python

You can use dict.update:

d.update({'a': 10, 'c': 200, 'c': 30})

This will overwrite the values for existing keys and add new key-value-pairs for keys that do not already exist.

Solution 2 - Python

You can also simply use the multiple assigment semantics:

d['a'], d['b'], d['c'] = 10, 200, 30

Solution 3 - Python

You can always wrap it in a function:

def multiassign(d, keys, values):
    d.update(zip(keys, values))

Even if you didn't know about update, you could write it like this:

def multiassign(d, keys, values):
    for k, v in zip(keys, values):
        d[k] = v

Or you can even write a dict subclass that gives you exactly the syntax you wanted:

class EasyDict(dict):
    def __getitem__(self, key):
        if isinstance(key, tuple):
            return [super().__getitem__(k) for k in key]
        else:
            return super().__getitem__(key)
    def __setitem__(self, key, value):
        if isinstance(key, tuple):
            self.update(zip(key, value))
        else:
            super().__setitem__(key, value)
    def __delitem__(self, key, value):
        if isinstance(key, tuple):
            for k in key: super().__delitem__(k)
        else:
            super().__setitem__(key, value)

Now:

>>> d = {'a': 1, 'd': 4}
>>> multiassign(d, ['a', 'b', 'c'], [10, 200, 300])
>>> d
{'a': 10, 'b': 200, 'c': 300, 'd': 4}
>>> d2 = EasyDict({'a': 1, 'd': 4})
>>> d2['a', 'b', 'c'] = 100, 200, 300
>>> d2
{'a': 10, 'b': 200, 'c': 300, 'd': 4}

Just be aware that it will obviously no longer be possible to use tuples as keys in an EasyDict.

Also, if you were going to use this for something serious, you'd probably want to improve the error handling. (d['a', 'b'] = 1 will give a cryptic message about zip argument #2 must support iteration, d['a', 'b', 'c'] = 1, 2 will silently work and do nothing to c, etc.)

Solution 4 - Python

A speed comparison, from the worst to the best:

Python 3.5.3 |Continuum Analytics, Inc.| (default, May 15 2017, 10:43:23) [MSC v.1900 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import numpy.random as nprnd
   ...: d = dict([(_, nprnd.rand()) for _ in range(1000)])
   ...: values = nprnd.randint(1000, size=10000)
   ...: keys = nprnd.randint(1000, size=10000)
   ...: def multiassign(d, keys, values):
   ...:     for k, v in zip(keys, values):
   ...:         d[k] = v
   ...:
   ...: d1 = dict(d)
   ...: %timeit multiassign(d1, keys, values)
   ...: d1 = dict(d)
   ...: %timeit {**d1, **{keys[i]: values[i] for i in range(len(keys))}}
   ...: d1 = dict(d)
   ...: %timeit d1.update(zip(keys, values))
   ...: d1 = dict(d)
   ...: %timeit {*d1.items(), *zip(keys, values)}
   ...: d1 = dict(d)
   ...: %timeit {**d1, **{key: value for key, value in zip(keys, values)}}
   ...: d1 = dict(d)
   ...: %timeit {**d1, **dict(zip(keys, values))}
4 ms ± 25.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.66 ms ± 29.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.17 ms ± 31.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.81 ms ± 98.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.38 ms ± 75.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.96 ms ± 21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

So the clear winner is recreation of dictionary from dictionaries.

Solution 5 - Python

You could use a dictionary comprehension e.g.

letters, nos = ['a','b','c'], [1,2,3]
d = {letters[i]: nos[i] for i in range(len(nos))}

output:

> {'a': 1, 'c': 3, 'b': 2}

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
QuestionoziView Question on Stackoverflow
Solution 1 - PythonAamir RindView Answer on Stackoverflow
Solution 2 - PythonDelganView Answer on Stackoverflow
Solution 3 - PythonabarnertView Answer on Stackoverflow
Solution 4 - PythonSklavitView Answer on Stackoverflow
Solution 5 - PythonChrisProsserView Answer on Stackoverflow