Nested dictionary comprehension (2 level) - python

I have a list of dictionary objects
data = [
{
'id': 1,
'parent_id': 101 ,
'name': 'A'
},
{
'id': 2,
'parent_id': 101,
'name': 'B'
},
{
'id': 3,
'parent_id': 102,
'name': 'C'
},
{
'id': 4,
'parent_id': 102,
'name': 'D'
}
]
I want to convert this to a nested dictionary.
Structure:
{
parent_id_value: {
name_value: id_value
}
}
Result of the sample list of dictionary object should be like this
{
101: {
'A': 1,
'B': 2
},
102: {
'C': 3,
'D': 4
}
}
I know we can run a for loop and use setdefault to set/get paren_id value and then add the name and id as key, value
new_dic = {}
for i in data:
new_dic.setdefault(i['parent_id'], {})[i['name']] = i['id']
print(new_dic)
But I am looking for a more pythonic way, meaning is it possible through dictionary comprehension?

So you want to play the comprehension game and you want to see a pro player at it.
Forget about itertools, forget about multiple statements. Here is the ultimate comprehension that will make any programmer working on your code throw the keyboard away and leave the room cursing you.
data = {parent_id: {d["name"]: d["id"] for d in [i for i in data if i["parent_id"] == parent_id]} for parent_id in set((j["parent_id"] for j in data))}
But for real though, don't do this in your code if it's going to be shared with someone.

First, sort the list using operator.itemgetter to supply the key:
data.sort(key=itemgetter('parent_id'))
Then use itertools.groupby to group the intended sections in a nested dict-comprehension:
data = {
key: {item['name']: item['id'] for item in group}
for key, group in groupby(data, itemgetter('parent_id'))
}
I don't recommend writing a one-liner, but you can do it with sorted:
data = {
key: {item['name']: item['id'] for item in group}
for key, group in groupby(sorted(data, key=itemgetter('parent_id')), itemgetter('parent_id'))
}

Related

pandas two lists of dict in one variable into one list of dict in one variable

I have two lists of dict in one variable want to combine to one list of dict in one variable, how to do?
df30 = df10.merge(df21, on='id', how='inner')
df30 = df30.to_dict('records')
The variable of df30 inside have 2 lists.
[
{
'id': 2101,
'percent': -10.213240935732046
}
]
[
{
'id': 2100,
'percent': -77.0623742454728
}
]
I want to combine them into one list of dict, how do I do that?
[
{
'id': 2101,
'percent': -10.213240935732046
},
{
'id': 2100,
'percent': -77.0623742454728
}
]
or create two new variables for two lists in df30 and combine the two variables is it possible?
Quite confused here, but:
l1 = [{'A':1, 'W':10}]
l2 = [{'B':2, 'Y':20}]
l1 + l2
Output:
[{'A': 1, 'W': 10}, {'B': 2, 'Y': 20}]

How to set specific attributes of a dictionary to []

Let us imagine the following dictionary
dictionary = {
"key1": {
"value": [1, 3, 5],
},
"key2": {
"value": [1, 2, -1],
},
}
Is it possible to set all the "values" to [] without iterating over the dictionary keys? I want something like dictionary[]["value"]=[] such that all "value" attributes are set to []. But that doesn't work.
Because you need to avoid iteration, here is a little hacky way of solving the case.
Convert dictionary to string, replace and then back to dictionary:
import re, ast
dictionary = {
"key1": {
"value": [1, 3, 5],
},
"key2": {
"value": [1, 2, -1],
},
}
print(ast.literal_eval(re.sub(r'\[.*?\]', '[]', str(dictionary))))
# {'key1': {'value': []}, 'key2': {'value': []}}
I'm going to take a different tack here. Your question is a little misinformed. The implication is that it's "better" to avoid iterating dictionary keys. As mentioned, you can iterate over dictionary values. But, since internally Python stores dictionaries via two arrays, iteration is unavoidable.
Returning to your core question:
I want something like dictionary[]["value"]=[] such that all "value"
attributes are set to [].
Just use collections.defaultdict:
from collections import defaultdict
d = {k: defaultdict(list) for k in dictionary}
print(d['key1']['value']) # []
print(d['key2']['value']) # []
For the dictionary structure you have defined, this will certainly be more efficient than string conversion via repr + regex substitution.
If you insist on explicitly setting keys, you can avoid defaultdict at the cost of an inner dictionary comprehension:
d = {k: {i: [] for i in v} for k, v in dictionary.items()}
{'key1': {'value': []}, 'key2': {'value': []}}

How to get all values for the same key from key-value pairs in python dictionary

How to iterate over all key value pairs of a dictionary and build all different values list for the same key using python.
Sample data:
"list": [
{
"1": 1
},
{
"1": 8
},
{
"1": 9
},
{
"1": 1
},
{
"2": 8
},
{
"2": 10
}
],
For the above list, I need to build a list like:
[{"1":[1,8,9]}, {"2":[8,10]}]
This will give you what you want
import collections
input_ = {'list': [{'1': 1}, {'1': 8}, {'1': 9}, {'1': 1}, {'2': 8}, {'2': 10}]}
result = collections.defaultdict(list)
for elem in input_['list']:
key, value = next(iter(elem.items())) # best way to extract data from your strange format
if value not in result[key]:
result[key].append(value)
result = [dict(result)] # put it in the strange format you want
outputs
[{'1': [1, 8, 9], '2': [8, 10]}]
However I strongly recommend reconsidering how you structure your data. For example, your input should be a list of tuples, not a list of dictionaries.
this should do the trick - but please notice that doing a dictionary with only one key and value is not the way to save data.
new_dict = {}
for pair in your_list:
for key in pair:
if key in new_dict:
new_dict[key] = new_dict[key].append(pair[key])
else:
new_dict[key] = [pair[key]]
print new_dict
new_dict is a dictionary with key -> list of values mapping

How to join two lists of dictionaries in Python?

I have the following simple data structures:
teams = [ { 'league_id': 1, 'name': 'Kings' }, { 'league_id': 1, 'name': 'Sharkls' }, { 'league_id': 2, 'name': 'Reign' }, { 'league_id': 2, 'name': 'Heat' } ]
leagues = [ { 'league_id': 1, 'name': 'League 1' }, { 'league_id': 2, 'name': 'League 2' } ]
And I have the following dict comprehension:
league_teams = { x['league_id']: [ t['name']
for t in teams if t['league_id'] == x ['league_id'] ]
for x in leagues }
Which yields:
{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}
Is there a simpler way using itertools or something to get that dict? This feels a little cumbersome.
Here's an adaptation of Moinuddin Quadri's O(n+m) solution that catches the "empty league" case, and which incidentally does not require any modules to be imported. The dict output does double-duty as his league_ids set, and since it's pre-initialized, it does not need to be a collections.defaultdict:
output = { league['league_id']:[] for league in leagues }
for team in teams:
if team['league_id'] in output:
output[team['league_id']].append(team['name'])
print(output)
The output is:
{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}
You do not need itertools here, instead collections.defaultdict is better choice. Complexity of your solution is O(n*m) whereas with defaultdict, it will be O(n+m).
You can achieve what you want like:
from collections import defaultdict
# create set to store `league_id` in `leagues`. Set holds unique
# values and also searching in set is faster than in normal list
leagues_id = set([item['league_id'] for item in leagues])
my_dict = defaultdict(list)
for item in teams:
if item['league_id'] in leagues_id:
my_dict[item['league_id']].append(item['name'])
where at the end my_dict will hold the value:
{1: ['Kings', 'Sharkls'], 2: ['Reign', 'Heat']}
Edit: In case you also want entry in my_dict for the league_id present in leagues, but not in teams, you need to explictly make entries like:
for leagues_id in leagues_ids:
_ = my_dict[leagues_id] # Will create empty list for such ids
Checking t['league_id'] == x['league_id'] looks not necessary.
You can simplify with:
import collections
league_teams = collections.defaultdict(list)
for t in teams:
league_teams[t['league_id']].append(t['name'])
If you really want itertools for that:
import itertools
league_teams = {k: [t['name'] for t in g]
for k, g in itertools.groupby(teams, key=lambda t: t['league_id'])}
But it will only work if the teams list is sorted.

Python: Sorting an array based on a subvalue [duplicate]

This question already has answers here:
How do I sort a dictionary by value?
(34 answers)
Closed 8 years ago.
I have the following data structure:
[
{ some: thing9,
key: 9,
},
{ some: thing3,
key: 3,
},
{ some: thing2,
key: 2,
},
{ some: thing1,
key: 1,
}
]
How can I sort this array based on the key value of the dictionary so I get:
[
{ some: thing1,
key: 1,
},
{ some: thing2,
key: 2,
},
{ some: thing3,
key: 3,
},
{ some: thing9,
key: 9,
}
]
Thanks
sorted(data, key=operator.itemgetter('key'))
The Sorting HOWTO explains this in more detail. But the basic idea is that all sort-related functions take a key argument, a callable that's applied to each value before comparing the values.
So, we want key to take one of the elements of your list, and return the thing you want to sort by. The elements are dicts, and you want to sort by their key item. The itemgetter function does exactly what you want. (If that function weren't available, you could use, e.g., lambda item: item['key'] instead.)
If you prefer to use lambda expressions, this is also an suitable way of solving your problem:
sorted(data, key=lambda x: x['key'])
So:
from pprint import pprint
data = [
{ 'some': 'thing9',
'key': 9,
},
{ 'some': 'thing3',
'key': 3,
},
{ 'some': 'thing2',
'key': 2,
},
{ 'some': 'thing1',
'key': 1,
}
]
pprint(sorted(data, key=lambda x:x['key']))
outputs
[{'key': 1, 'some': 'thing1'},
{'key': 2, 'some': 'thing2'},
{'key': 3, 'some': 'thing3'},
{'key': 9, 'some': 'thing9'}]

Categories

Resources