convert list of dict into dict python - pythonic way - python

input:
list = [{'key': '1234', 'value': 100.00}, {'key': '2345', 'value': 200.0}]
output:
{'1234': 100.00, '2345': 200.0}
I now this can be achieved by looping over. Is there any pythonic way to do the same?

You're right that a loop would be straightforward.
result = {}
for curr in lst:
result[curr['key']] = result[curr['value']]
We can shorten it a bit with a dictionary comprehension. This says the same thing but more compactly
result = { curr['key']: curr['value'] for curr in lst }

By "pythonic", I take that to mean using things like dict comprehension:
list = [{'key': '1234', 'value': 100.00}, {'key': '2345', 'value': 200.0}]
output = {item["key"]: item["value"] for item in list}
print(output) # {'1234': 100.00, '2345': 200.0}
By the way, you might want to rename list to something else, because list is an internal python function.

Just for funsies, a method that involves executing no Python-level code per-item:
from operator import itemgetter
lst = [{'key': '1234', 'value': 100.00}, {'key': '2345', 'value': 200.0}]
dct = dict(map(itemgetter('key', 'value'), lst))
The itemgetter, when passed a dict from lst, extracts the key and value and returns them as a tuple. map ensures this is done for each dict in lst, and the dict constructor knows how to turn an iterable of two-tuples into a new dict, all without executing a single byte code for any given item (all bytecode involved is fixed overhead to set everything up, then the map iterator is run to exhaustion to populate the dict without returning control to the byte code eval loop, as long as all keys and values involved are built-ins implemented in C).

Just use the values of each dict to make the new dict:
dict(map(dict.values, lst))
{'1234': 100.0, '2345': 200.0}
Caution the dicts need to be in key/value order like in your example for this to work properly. Which also means this will work fine in Python 3 but you will need to use an collections.OrderedDict in python 2.7

It can be writed in one line like this with nested comprehension:
data = [{'key': '1234', 'value': 100.00}, {'key': '2345', 'value': 200.0}]
new_dict = {r[0]: r[1] for r in [list(d.values()) for d in data]}
Thanks for ShadowRanger it can be simplified to:
new_dict = dict(d.values() for d in data)
It works only with Python 3.7+ with ordered dicts.

Related

Adding multiple new key-value pairs to a nested dictionary

I am new to python and I am trying to add key-value pairs to a nested dictionary. I tried a few approaches but I am not able to do it properly. This is the code that I have written:
dict1 = {}
dict1['name'] = {'domain': "something"}
i=0
while i < 10:
new = 'route'+str(i)
dict1['name']['routes'] = {new: {'bit_value': i}}
i = i+1
print(dict1)
This is the output I am getting:
{'name': {'domain': 'something', 'routes': {'route9': {'bit_value': 9}}}}
This is the kind of output that I want:
{'name': {'domain': 'something', 'routes': {'route1': {'bit_value': 1}, 'route2': {'bit_value': 2}, 'route3': {'bit_value': 3}, 'route4': {'bit_value': 4} ...}}}
I tried using this version as well, but it throws a Keyerror:
import collections
dict1 = collections.defaultdict(dict)
dict1['name'] = {'domain': "something"}
i = 0
while i < 10:
new = 'route'+str(i)
dict1['name']['routes'][new] = {'bit_value': i}
i = i+1
print(dict1)
Error message:
dict1['name']['routes'][new] = {'bit_value': i}
KeyError: 'routes'
It would be nice if this problem can be solved without changing into a for loop as the while loop will make it easier for me to integrate this with rest of the code that I have written. I would really appreciate if someone can help me.
First create the routes sub-dictionary, then insert items.
import collections
dict1 = collections.defaultdict(dict)
dict1['name'] = {'domain': "something"}
i = 0
##########
dict1['name']['routes'] = {}
##########
while i < 10:
new = 'route'+str(i)
dict1['name']['routes'][new] = {'bit_value': i}
i = i+1
print(dict1)
In your original solution, dict1['name']['routes'] is replaced with a new dictionary with only 1 key every time.
In your alternative version, dict1 is a defaultdict. So you can access e.g. dict1['randomkey'] without initializing it, but dict1['name'] or dict1['name']['routes'] is not a defaultdict. defaultdict(dict) means the values are normal dictionaries. If you need the values to be defaultdict as well, you can do defaultdict(defaultdict(dict))
But that's not what you want. You don't actually need to deal with default key values. You only need to initialize dict1['name']['routes'] once to a normal dictionary:
dict1 = {'name': {'domain': 'something', 'routes': {}}}
for i in range(10):
dict1['name']['routes'][f'route{i}'] = {'bit_value': i}
A few bonus tips
Don't mix 'string' with "string"
Use for i in range(10) instead of a while loop. Much simpler and easier to read
Use f-string to format string f'route{i}'
As a matter of fact, your code can also be achieved with dictionary comprehension
dict1 = {'name': {'domain': 'something'}}
dict1['name']['routes'] = {f'route{i}': {'bit_value': i} for i in range(10)}

Making dictionary from two lists

I have two lists
l1 = ['cat','dog']
l2= [1,2]
Now I want to make a dictionary like this:
dict { {'name':cat,'id'=1}{'name':dog,'id'=2}}
I am using zip but that's not fulfilling my requirement.
result = [{'name': name, 'id': id} for (name, id) in zip(l1, l2)]
It doesn't make sense for the container all the individual dicts are in to be a dict as well (unless you want to key it on, say, id).
If you have a lot of keys and you don't want to create dict comprehension and declare what goes where.
l1 = ['cat','dog']
l2= [1,2]
[dict(zip(['name', 'id'], el)) for el in zip(l1,l2)]
Output:
[{'id': 1, 'name': 'cat'}, {'id': 2, 'name': 'dog'}]

Python Dict Comprehension to Create and Update Dictionary

I have a list of dictionaries (data) and want to convert it into dictionary (x) as below.
I am using following ‘for loop’ to achieve.
data = [{'Dept': '0123', 'Name': 'Tom'},
{'Dept': '0123', 'Name': 'Cheryl'},
{'Dept': '0123', 'Name': 'Raj'},
{'Dept': '0999', 'Name': 'Tina'}]
x = {}
for i in data:
if i['Dept'] in x:
x[i['Dept']].append(i['Name'])
else:
x[i['Dept']] = [i['Name']]
Output:
x -> {'0999': ['Tina'], '0123': ['Tom', 'Cheryl', 'Raj']}
Is it possible to implement the above logic in dict comprehension or any other more pythonic way?
The dict comprehension, even though not impossible, might not be the best choice. May I suggest using a defaultdict:
from collections import defaultdict
dic = defaultdict(list)
for i in data:
dic[i['Dept']].append(i['Name'])
It seems way too complicated to be allowed into any code that matters even the least bit, but just for fun, here you go:
{
dept: [item['Name'] for item in data if item['Dept'] == dept]
for dept in {item['Dept'] for item in data}
}

Adding a key value pair to a list of dicts based on another list Python

Sorry if the title is not clear, but here is what I'm trying to achieve.
I have a list of dicts :
l = [{'name': 'inAnalysis'}, {'name': 'inQuest'}, {'name': 'inDevelopment'}]
And a sort of translation table like this :
tr = {'inAnalysis' : 1, 'inDevelopment' : 2, 'inQuest' : 3}
I want to add the key value to l like this :
l = [{'name': 'inAnalysis', 'order' : 1},
{'name': 'inQuest', 'order' : 3},
{'name': 'inDevelopment', 'order' : 2}]
How can I match the value of l with the key of tr and get its value with the key order and add it to l? Any help would be appreciated. I'm using Python 2.6.
You can use list comprehension to dynamically generate the dictionaries like this
print [{"name":dic["name"], "order":tr[dic["name"]]} for dic in l]
Output
[{'name': 'inAnalysis', 'order': 1},
{'name': 'inQuest', 'order': 3},
{'name': 'inDevelopment', 'order': 2}]
Alternatively, you can use the following
for dic in l: dic["order"] = tr[dic["name"]]
this modifies the dictionaries in-place.
If you want to modify the existing dictionaries in place (note that thefoutheye's solution makes new dictionaries which could concievably be a problem if something else in your code is holding a reference to the dictionaries in the list, rather than the list itself) you can do:
for my_dict in l:
my_dict['order'] = tr[my_dict['name']]

Can I use set comprehension to create a list of dict from a bigger list of dict?

I'm working with denormalized tables which provides a bit of challenge when it comes to extracting unique information. If the tables were normalized:
unique_data = list({d['value'] for d in mydata})
would do the trick.
But the tables aren't normalized.
Can I create a set of dict that I can then turn into list? Something like (this gives me an error):
unique_data_with_id = list({{'id':d['id'], 'value':d['value']} for d in mydata})
Dictionaries are mutable, so you can't put them in a set. One way around this is to use a namedtuple instead of a dictionary:
IdValueTuple = collections.namedtuple("IdValueTuple", "id value")
unique_data_with_id = list({IdValueTuple(d["id"], d["value"]) for d in mydata})
{{'id':d['id'], 'value':d['value']} for d in mydata}
creates a set ofdicts. Because dicts are mutable, they aren't hashable and a set needs hashable elements.
Try tuple instead:
{(d['id'], d['value']) for d in mydata}
Note that I quite like Sven Marnach's usage of a namedtuple here.
More because it's occasionally useful in other contexts, you could use a frozenset as an intermediate object:
>>> pprint.pprint(mydata)
[{'id': 1, 'ignore': 92, 'value': 'a'},
{'id': 2, 'ignore': 92, 'value': 'b'},
{'id': 1, 'ignore': 92, 'value': 'a'}]
>>> keep_keys = "id", "value"
>>> [dict(s) for s in {frozenset((k, d[k]) for k in keep_keys) for d in mydata}]
[{'id': 1, 'value': 'a'}, {'id': 2, 'value': 'b'}]

Categories