Python: Convert a list into a bidimensional mapping dictionary - python

I have a list of dictionaries:
[
{'student_id': 'john', 'exercise_id': '3', 'answer': 20},
{'student_id': 'john', 'exercise_id': '2', 'answer': 10},
{'student_id': 'jane', 'exercise_id': '2', 'answer': 30},
]
What is an elegant/short way to convert that into a [exercise x student] "mapping table" dictionary?
Like so:
{
'3':{
'john': {'student_id': 'john', 'exercise_id': '3', 'answer': 20}
},
'2': {
'john': {'student_id': 'john', 'exercise_id': '2', 'answer': 10},
'jane': {'student_id': 'jane', 'exercise_id': '2', 'answer': 30}
}
}
You can assume the map contains at most one answer per exercise per student.

The straight forward way would be to gather them in a dictionary, like this
d = {}
for item in l:
d.setdefault(item["exercise_id"], {}).setdefault(item["student_id"], []).append(item)
print(d)
Output
{'2': {'jane': [{'answer': 30, 'exercise_id': '2', 'student_id': 'jane'}],
'john': [{'answer': 10, 'exercise_id': '2', 'student_id': 'john'}]},
'3': {'john': [{'answer': 20, 'exercise_id': '3', 'student_id': 'john'}]}}
First, if the item["exercise_id"] is not there in d, then a new dictionary will be set as the value and then in that dictionary, if item["student_id"] is not there, we set an empty list as the value and we append the current dictionary in that list.

This generates the output you want:
output = {}
for value in data:
output.setdefault(value['exercise_id'], {})[value['student_id']] = value
print output

Related

Remove a dictionary from list if other list contains same dictionary

I am solving a specific problem and I would like to find out what is the most pythonic way. I have two list of dictionaries, for example:
l1 = [{id: '1', grade: 'A'}, {id: '2', grade: 'B'}, {id: '3', grade: 'A'}]
l2 = [{id: '1', grade: 'A'}, {id: '2', grade: 'B'}, {id: '3', grade: 'Unavailable'}]
There are always the same ids in boths lists, only the grades differ. Now I want to write a list comprehension to remove from l1 all the dictionaries that have Unavailable grade in l2. Meaning in this case I want to remove dict with id:3.
Can someone help me out? Much thanks
You could make an intermediate set of the ids you want to remove.
>>> l1 = [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}, {'id': '3', 'grade': 'A'}]
>>> l2 = [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}, {'id': '3', 'grade': 'Unavailable'}]
>>> unavailable = {g['id'] for g in l2 if g['grade'] == 'Unavailable'}
>>> l1_fixed = [g for g in l1 if g['id'] not in unavailable]
>>> l1_fixed
[{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}]
This works assuming l1 and l2 are of the same length. Try:
for dicIndex in range(len(l1)):
if 'Unavailable' in l2[dicIndex].values():
l1.pop(dicIndex)
print(l1)
Output:
[{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}]
You can do this with zip,
In [1]: [d1 for d1,d2 in zip(l1, l2) if d2.get('grade') != 'Unavailable']
Out[1]: [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}]
If the list is not ordered so we need to sort before the list comprehension,
l1 = sorted(l1, key=lambda x:x.get('id'))
l2 = sorted(l2, key=lambda x:x.get('id'))
output = [d1 for d1,d2 in zip(l1, l2) if d2.get('grade') != 'Unavailable']
I believe this is the Pythonic way to do it
Using List Comprehension:
l1 = [{"id": '1', "grade": 'A'}, {"id": '2', "grade": 'B'}, {"id": '3', "grade": 'A'}]
l2 = [{"id": '1', "grade": 'A'}, {"id": '2', "grade": 'B'}, {"id": '3', "grade": 'Unavailable'}]
# Incase grade is always the same in l1 and l2
# Except it can have a value "Unavailable" in l2
l1 = [item for item in l2 if item['grade'] != 'Unavailable']
# Otherwise if grade can be a different value in both lists for the same index
l1 = [l1[i] for i in range(len(l2)) if l2[i]["grade"] != 'Unavailable']
Output:
>>> [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}] # l1_method_1
>>> [{'id': '1', 'grade': 'A'}, {'id': '2', 'grade': 'B'}] # l1_method_2

How to create an empty list of dictionaries and populate afterwords?

I need to initialize an empty List of Dictionary(LOD) which must have the following keys in it. "id","name","age", "gender". I want to create a loop/nested loop that starts populating the LOD. For poppulating I have a list which has ID's and the rest of the keys are generated using the random function.
The ID list looks like this: id = ['1','2','3']
The result must look something like this.
LOD = [
{
'id': '1',
'name':'122121',
'age':'2131',
'gender':'121'
},
{
'id': '2',
'name':'122121',
'age':'2131',
'gender':'121'
},
{
'id': '3',
'name':'122121',
'age':'2131',
'gender':'121'
},
]
CJDB already does what you want. But if you'd perhaps prefer another approach:
ids = ['1','2','3']
keys = ["name","age", "gender"]
LOD = []
and then populate your list with dictionaries
for i in ids:
your_dictionary = {"id": i}
for key in keys:
your_dictionary[key] = '{}_rnd_function_output'.format(key)
LOD.append(your_dictionary)
And the output would be
>>> LOD
[{'id': '1',
'name': 'name_rnd_function_output',
'age': 'age_rnd_function_output',
'gender': 'gender_rnd_function_output'},
{'id': '2',
'name': 'name_rnd_function_output',
'age': 'age_rnd_function_output',
'gender': 'gender_rnd_function_output'},
{'id': '3',
'name': 'name_rnd_function_output',
'age': 'age_rnd_function_output',
'gender': 'gender_rnd_function_output'}
]
You might consider having a sub-dictionaries within a dictionary. Your ids would be keys for main dictionary and sub-dictionaries would be values.
LOD = {}
for i in ids:
LOD[i] = {}
for key in keys:
LOD[i][key] = '{}_rnd_function_output'.format(key)
And the output
>>> LOD
{'1': {'name': 'name_rnd_function_output',
'age': 'age_rnd_function_output',
'gender': 'gender_rnd_function_output'},
'2': {'name': 'name_rnd_function_output',
'age': 'age_rnd_function_output',
'gender': 'gender_rnd_function_output'},
'3': {'name': 'name_rnd_function_output',
'age': 'age_rnd_function_output',
'gender': 'gender_rnd_function_output'}}
You can use a dictionary-comprehension for this:
ids = ['1','2','3']
LOD = [
{
'id': i,
'name':'122121',
'age':'2131',
'gender':'121'
} for i in ids
]
Output:
>>> LOD
[{'id': '1', 'name': '122121', 'age': '2131', 'gender': '121'},
{'id': '2', 'name': '122121', 'age': '2131', 'gender': '121'},
{'id': '3', 'name': '122121', 'age': '2131', 'gender': '121'}]
Or, using the random module:
import random
ids = ['1','2','3']
LOD = [
{
'id': i,
'name': str(random.randint(100000, 999999)),
'age': str(random.randint(1000, 9999)),
'gender': str(random.randint(100, 999))
} for i in ids
]
Output:
>>> LOD
[{'id': '1', 'name': '727325', 'age': '5367', 'gender': '238'},
{'id': '2', 'name': '316019', 'age': '8963', 'gender': '702'},
{'id': '3', 'name': '464023', 'age': '4324', 'gender': '155'}]
Note that you should not use id as a variable name as it shadows the builtin python id object.
You can do it by initializing dict objects in list comprehensions
keys = ['id', 'name', 'age', 'gender']
ids = ['1', '2', '3']
LOD = [dict((key, i if key == 'id' else random.randint(1, 100)) for key in keys) for i in ids]
print(LOD)
'''
[{'id': '1', 'name': 34, 'age': 10, 'gender': 57},
{'id': '2', 'name': 64, 'age': 13, 'gender': 21},
{'id': '3', 'name': 11, 'age': 17, 'gender': 2}]
'''

Update dictionary keys inside a list based on another dictionary key value pairs

I have a list which has nested dictionary inside it and also a dictionary with respective key pair values.
I am trying to map the key from dict2 to keys for the dictionary elements inside the list.
list = [{'name': 'Megan', 'Age': '28', 'occupation': 'yes', 'race': 'american', 'children': 'yes'}, {'name': 'Ryan', 'Age': '25', 'occupation': 'no', 'race': 'american', 'intern': 'yes'}]
The respective dictionary which holds the correct keys is
dict_map = {'occupation': 'service', 'intern': 'employee', 'race': 'ethnicity'}
I am new to python so far I am trying to go through stackoverflow pages to get an output tried few as well but not able to get the desired result so far.
The closet I got was with this Python Dictionary: How to update dictionary value, base on key - using separate dictionary keys
The final output should be:
[{'name': 'Megan', 'Age': '28', 'service': 'yes', 'ethnicity': 'american', 'children': 'yes'}, {'name': 'Ryan', 'Age': '25', 'service': 'no', 'ethnicity': 'american', 'employee': 'yes'}]
you could try this:
note that i renamed your list to lst (list is abuilt-in type that you should never overwrite!)
lst = [
{
"name": "Megan",
"Age": "28",
"occupation": "yes",
"race": "american",
"children": "yes",
},
{
"name": "Ryan",
"Age": "25",
"occupation": "no",
"race": "american",
"intern": "yes",
},
]
for dct in lst:
for old_key, new_key in dict_map.items():
if old_key not in dct:
continue
dct[new_key] = dct[old_key]
del dct[old_key]
Using a list comprehension with dict.get
Ex:
lst = [{'name': 'Megan', 'Age': '28', 'occupation': 'yes', 'race': 'american', 'children': 'yes'}, {'name': 'Ryan', 'Age': '25', 'occupation': 'no', 'race': 'american', 'intern': 'yes'}]
dict_map = {'occupation': 'service', 'intern': 'employee', 'race': 'ethnicity'}
result = [{dict_map.get(k, k): v for k, v in i.items()} for i in lst]
print(result)
Output:
[{'Age': '28',
'children': 'yes',
'ethnicity': 'american',
'name': 'Megan',
'service': 'yes'},
{'Age': '25',
'employee': 'yes',
'ethnicity': 'american',
'name': 'Ryan',
'service': 'no'}]

Append Python List of Dictionaries by loops

I have 2 Python List of Dictionaries:
[{'index':'1','color':'red'},{'index':'2','color':'blue'},{'index':'3','color':'green'}]
&
[{'device':'1','name':'x'},{'device':'2','name':'y'},{'device':'3','name':'z'}]
How can I Append each dictionary of second list to the first list so as to get an output as:
[{'device':'1','name':'x'},{'index':'1','color':'red'},{'index':'2','color':'blue'},{'index':'3','color':'green'}]
[{'device':'2','name':'y'},{'index':'1','color':'red'},{'index':'2','color':'blue'},{'index':'3','color':'green'}]
[{'device':'3','name':'z'},{'index':'1','color':'red'},{'index':'2','color':'blue'},{'index':'3','color':'green'}]
I think that the following code answers your question:
indexes = [
{'index':'1','color':'red'},
{'index':'2','color':'blue'},
{'index':'3','color':'green'}
]
devices = [
{'device':'1','name':'x'},
{'device':'2','name':'y'},
{'device':'3','name':'z'}
]
new_lists = [[device] for device in devices]
for new_list in new_lists:
new_list.extend(indexes)
I don't know where you wanted to save your result lists, so I printed them out:
d1 = [{'index':'1','color':'red'},{'index':'2','color':'blue'},{'index':'3','color':'green'}]
d2 = [{'device':'1','name':'x'},{'device':'2','name':'y'},{'device':'3','name':'z'}]
for item in d2:
print ([item] + d1)
The output:
[{'name': 'x', 'device': '1'}, {'index': '1', 'color': 'red'}, {'index': '2', 'color': 'blue'}, {'index': '3', 'color': 'green'}]
[{'name': 'y', 'device': '2'}, {'index': '1', 'color': 'red'}, {'index': '2', 'color': 'blue'}, {'index': '3', 'color': 'green'}]
[{'name': 'z', 'device': '3'}, {'index': '1', 'color': 'red'}, {'index': '2', 'color': 'blue'}, {'index': '3', 'color': 'green'}]
(Don't be confused by order of items in individual directories as directories are not ordered.)

Merging nested dictionaries by keys preserving different values

I have two list of nested dictionaries with the same keys, but different values:
d1 = {
'distilled ': [{'water': '45'}, {'vodka': '9'}, {'vinegar': '7'}, {'beer': '6'}, {'alcohol': '5'}, {'whiskey': '5'}],
'planted': [{'tree': '30'}, {'seed': '28'}, {'flower': '20'}, {'plant': '7'}, {'bomb': '4'}, {'garden': '2'}]
}
and
d2 = {
'distilled ': [{'water': '14'}, {'vinegar': '9'}, {'wine': '8'}, {'alcohol': '8'}, {'liquid': '7'}, {'whiskey': '6'}, {'beer': '5'}],
'planted ': [{'flower': '28'}, {'tree': '18'}, {'seed': '9'}, {'vegetable': '4'}, {'bush': '3'}, {'grass': '3'}, {'garden': '3'}]
}
I want to merge them in a way that preserves the values and merges only the keys in the nested dictionaries. So that the outcome would look like:
{
'distilled ': [('water', '45', '14'), ('vodka', '9'), ('vinegar', '7', '9'), ('beer', '6', '5'), ('alcohol', '5'), ('whiskey', '5'), ('wine', '8')],
'planted': [('tree', '30', '18'), ('seed', '28', '9'), ('flower', '20', '7'), ('plant', '7'), ('bomb', '4'), ('garden', '2', '3')]
}
I tried merging the two using:
d_merged = { k: [ d1[k], d2_to_compare[k] ] for k in d1 }
but the in the outcome only the values of the first dictionary are presented, obviously. Do you have any ideas on how to fix this? Thank you very much in advance.
I am not sure which way to take from here. Would really appreciate any suggestions! Thanks a lot.
dict only has one key-value pair is not a good idea, but anyway, we can work out like this:
d1 = {
'distilled': [{'water': '45'}, {'vodka': '9'}, {'vinegar': '7'}, {'beer': '6'}, {'alcohol': '5'}, {'whiskey': '5'}],
'planted': [{'tree': '30'}, {'seed': '28'}, {'flower': '20'}, {'plant': '7'}, {'bomb': '4'}, {'garden': '2'}]
}
d2 = {
'distilled': [{'water': '14'}, {'vinegar': '9'}, {'wine': '8'}, {'alcohol': '8'}, {'liquid': '7'}, {'whiskey': '6'}, {'beer': '5'}],
'planted': [{'flower': '28'}, {'tree': '18'}, {'seed': '9'}, {'vegetable': '4'}, {'bush': '3'}, {'grass': '3'}, {'garden': '3'}]
}
d3 = {}
for k, v in d1.items():
k1 = dict([d.items()[0] for d in d1[k]])
k2 = dict([d.items()[0] for d in d2[k]])
ret = []
for d in (set(k1.keys()) | set(k2.keys())):
ret.append((d, k1.get(d), k2.get(d)))
d3[k] = ret
print d3

Categories