Related
How can I turn a list of dicts like [{'a':1}, {'b':2}, {'c':1}, {'d':2}], into a single dict like {'a':1, 'b':2, 'c':1, 'd':2}?
Answers here will overwrite keys that match between two of the input dicts, because a dict cannot have duplicate keys. If you want to collect multiple values from matching keys, see How to merge dicts, collecting values from matching keys?.
This works for dictionaries of any length:
>>> result = {}
>>> for d in L:
... result.update(d)
...
>>> result
{'a':1,'c':1,'b':2,'d':2}
As a comprehension:
# Python >= 2.7
{k: v for d in L for k, v in d.items()}
# Python < 2.7
dict(pair for d in L for pair in d.items())
In case of Python 3.3+, there is a ChainMap collection:
>>> from collections import ChainMap
>>> a = [{'a':1},{'b':2},{'c':1},{'d':2}]
>>> dict(ChainMap(*a))
{'b': 2, 'c': 1, 'a': 1, 'd': 2}
Also see:
What is the purpose of collections.ChainMap?
Little improvement for #dietbuddha answer with dictionary unpacking from PEP 448, for me, it`s more readable this way, also, it is faster as well:
from functools import reduce
result_dict = reduce(lambda a, b: {**a, **b}, list_of_dicts)
But keep in mind, this works only with Python 3.5+ versions.
This is similar to #delnan but offers the option to modify the k/v (key/value) items and I believe is more readable:
new_dict = {k:v for list_item in list_of_dicts for (k,v) in list_item.items()}
for instance, replace k/v elems as follows:
new_dict = {str(k).replace(" ","_"):v for list_item in list_of_dicts for (k,v) in list_item.items()}
unpacks the k,v tuple from the dictionary .items() generator after pulling the dict object out of the list
For flat dictionaries you can do this:
from functools import reduce
reduce(lambda a, b: dict(a, **b), list_of_dicts)
You can use join function from funcy library:
from funcy import join
join(list_of_dicts)
>>> L=[{'a': 1}, {'b': 2}, {'c': 1}, {'d': 2}]
>>> dict(i.items()[0] for i in L)
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
Note: the order of 'b' and 'c' doesn't match your output because dicts are unordered
if the dicts can have more than one key/value
>>> dict(j for i in L for j in i.items())
If you don't need the singleton dicts anymore:
>>> L = [{'a':1}, {'b':2}, {'c':1}, {'d':2}]
>>> dict(map(dict.popitem, L))
{'a': 1, 'b': 2, 'c': 1, 'd': 2}
dict1.update( dict2 )
This is asymmetrical because you need to choose what to do with duplicate keys; in this case, dict2 will overwrite dict1. Exchange them for the other way.
EDIT: Ah, sorry, didn't see that.
It is possible to do this in a single expression:
>>> from itertools import chain
>>> dict( chain( *map( dict.items, theDicts ) ) )
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
No credit to me for this last!
However, I'd argue that it might be more Pythonic (explicit > implicit, flat > nested ) to do this with a simple for loop. YMMV.
this way worked for me:
object = [{'a':1}, {'b':2}, {'c':1}, {'d':2}]
object = {k: v for dct in object for k, v in dct.items()}
printing object:
object = {'a':1,'b':2,'c':1,'d':2}
thanks Axes
>>> dictlist = [{'a':1},{'b':2},{'c':1},{'d':2, 'e':3}]
>>> dict(kv for d in dictlist for kv in d.iteritems())
{'a': 1, 'c': 1, 'b': 2, 'e': 3, 'd': 2}
>>>
Note I added a second key/value pair to the last dictionary to show it works with multiple entries.
Also keys from dicts later in the list will overwrite the same key from an earlier dict.
If I do something like this
some_obj = {"a": 1, "b": 2, "c": 3}
first, *rest = some_obj
I'll get a list, but I want it in 2 dictionaries: first = {"a": 1} and rest = {"b": 2, "c": 3}. As I understand, I can make a function, but I wonder if I can make it in one line, like in javascript with spread operator.
I don't know if there is a reliable way to achieve this in one line, But here is one method.
First unpack the keys and values(.items()). Using some_obj only iterate through the keys.
>>> some_obj = {"a":1, "b":2, "c": 3}
>>> first, *rest = some_obj.items()
But this will return a tuple,
>>> first
('a', 1)
>>> rest
[('b', 2), ('c', 3)]
But you can again convert back to dict with just a dict call.
>>> dict([first])
{'a': 1}
>>> dict(rest)
{'b': 2, 'c': 3}
A oneliner inspired by Abdul Niyas P M's:
first, rest = dict([next(i := iter(some_obj.items()))]), dict(i)
Uses an assignment expression, introduced in Python 3.8 almost two years ago.
k = next(iter(some_obj)) # get the first key
first = {k: some_obj.pop(k)}
rest = some_obj
If you need to keep the original object intact - note this degrades from O(1) to O(n) in both time and space:
k = next(iter(some_obj))
rest = some_obj.copy()
first = {k: rest.pop(k)}
#AbdulNiyasPM's answer is perfectly fine, but since you asked for a one-liner, here's one way to do it (though you would have to do from operator import itemgetter first):
first, rest = map(dict, itemgetter(slice(0, 1), slice(1, None))(list(some_obj.items())))
If you prefer not to import anything, you can use a similar one-liner with a lambda function that takes one fixed argument and the rest as variable-length arguments:
first, rest = map(dict, (lambda f, *r: ((f,), r))(*some_obj.items()))
Demo: https://replit.com/#blhsing/ImpeccableEllipticalGeeklog
I have a very large nested dictionary and below I am showing a sample of it.
tmp_dict = {1: {'A': 1, 'B': 2},
2: {'A': 0, 'B': 0}}
The question is what is any better/efficient way to add a new pair key value to my existing nested dict. I am currently looping through the keys to do so. Here is an example:
>>> for k in tmp_dict.keys():
tmp_dict[k].update({'C':1})
A simple method would be like so:
for key in tmp_dict:
tmp_dict[key]['C']=1
Or, you could use dictionary comprehension, as sushanth suggested
tmp_dict = {k: {**v, 'C': 1} for k, v in timp_dict.items()}
You can read more about the asterisks (and why this works) here.
In terms of complexity, they are all O(N) time complexity (I think the dict comprehension maybe O(N^2)). So, your solution should have a relatively quick run time anyways.
Am trying to combine a dictionary and a list which has dictionaries and an empty dictionary
dict1 = {'a': 1, 'b': 2}
list1 = [{'c': 3}, {'d':4}]
emptydict = {}
emptylist = []
Trying to merge and make it a final dictionary which looks like below.
final = {'a': 1, 'b': 2, 'c': 3, 'd':4}
Code:
final = {**dict1, **list1[0], **list1[1], **emptydict, **emptylist}
Here I dont know the length of list1, can anyone suggest me a better way than this ?
dict.update updates an existing dictionary. Unfortunately it’s a mutating method that does not return a value. Therefore adapting it to functools.reduce requires a wrapper.
Due to this, I’d be tempted to use a good old loop:
final = dict(dict1)
for d in list1:
final.update(d)
But for completeness, here’s a way using functools.reduce:
import functools
def dict_update(d, v):
d.update(v)
return d
final = functools.reduce(dict_update, list1, dict1.copy())
If you are using python 3.3+, you can use ChainMap to merge list of dicts into a single dict. And then use ** operator to merge dict1 and dict(ChainMap(*list1)).
from collections import ChainMap
final = {**dict1, **ChainMap(*list1)}
I'm trying to write a function that turns strings of the form 'A=5, b=7' into a dict {'A': 5, 'b': 7}. The following code snippets are what happen inside the main for loop - they turn a single part of the string into a single dict element.
This is fine:
s = 'A=5'
name, value = s.split('=')
d = {name: int(value)}
This is not:
s = 'A=5'
d = {name: int(value) for name, value in s.split('=')}
ValueError: need more than 1 value to unpack
Why can't I unpack the tuple when it's in a dict comprehension? If I get this working then I can easily make the whole function into a single compact dict comprehension.
In your code, s.split('=') will return the list: ['A', '5']. When iterating over that list, a single string gets returned each time (the first time it is 'A', the second time it is '5') so you can't unpack that single string into 2 variables.
You could try: for name,value in [s.split('=')]
More likely, you have an iterable of strings that you want to split -- then your dict comprehension becomes simple (2 lines):
splitstrs = (s.split('=') for s in list_of_strings)
d = {name: int(value) for name,value in splitstrs }
Of course, if you're obsessed with 1-liners, you can combine it, but I wouldn't.
Sure you could do this:
>>> s = 'A=5, b=7'
>>> {k: int(v) for k, v in (item.split('=') for item in s.split(','))}
{'A': 5, ' b': 7}
But in this case I would just use this more imperative code:
>>> d = {}
>>> for item in s.split(','):
k, v = item.split('=')
d[k] = int(v)
>>> d
{'A': 5, ' b': 7}
Some people tend to believe you'll go to hell for using eval, but...
s = 'A=5, b=7'
eval('dict(%s)' % s)
Or better, to be safe (thanks to mgilson for pointing it out):
s = 'A=5, b=7'
eval('dict(%s)' % s, {'__builtins__': None, 'dict': dict})
See mgilson answer to why the error is happening. To achieve what you want, you could use:
d = {name: int(value) for name,value in (x.split('=',1) for x in s.split(','))}
To account for spaces, use .strip() as needed (ex.: x.strip().split('=',1)).
How about this code:
a="A=5, b=9"
b=dict((x, int(y)) for x, y in re.findall("([a-zA-Z]+)=(\d+)", a))
print b
Output:
{'A': 5, 'b': 9}
This version will work with other forms of input as well, for example
a="A=5 b=9 blabla: yyy=100"
will give you
{'A': 5, 'b': 9, 'yyy': 100}
>>> strs='A=5, b=7'
>>> {x.split('=')[0].strip():int(x.split('=')[1]) for x in strs.split(",")}
{'A': 5, 'b': 7}
for readability you should use normal for-in loop instead of comprehensions.
strs='A=5, b=7'
dic={}
for x in strs.split(','):
name,val=x.split('=')
dic[name.strip()]=int(val)
How about this?
>>> s
'a=5, b=3, c=4'
>>> {z.split('=')[0].strip(): int(z.split('=')[1]) for z in s.split(',')}
{'a': 5, 'c': 4, 'b': 3}
Since Python 3.8, you can use walrus operator (:=) for this kind of operation. It allows to assign variables in the middle of expressions (in this case, assign the list created by .split('=') to kv).
s = 'A=5, b=7'
{(kv := item.split('='))[0]: int(kv[1]) for item in s.split(', ')}
# {'A': 5, 'b': 7}
One feature is that it leaks the assigned variable, kv, outside the scope it was defined in. If you want to avoid that, you can use a nested for-loop where the inner loop is over a singleton list (as suggested in mgilson's answer).
{k: int(v) for item in s.split(', ') for k,v in [item.split('=')]}
Since Python 3.9, loops over singleton lists are optimized to be as fast as simple assignments, i.e. y in [expr] is as fast as y = expr.