Comparing key-value from two dictionaries Python - python

I have this
a = [{'name': 'John', 'supporterId': 1}, {'name': 'Paul', 'supporterId': 2}]
b = [{'dependent': 'Erick','supporterId': 2, 'email': 'erick#gmail.com'}, {'dependent': 'Anna', 'supporterId': 2, 'email': 'ana#gmail.com'}, {'dependent': 'George','supporterId': 13}]
and I need to check if the supporterId between a and b are equal and if so put the name_dependent and email inside the corresponding supporterId in a so for example the output to this should be:
c = [{'name': 'John', 'supporterId': 1}, {'name': 'Paul', 'supporterId': 2, 'data': {'dependent': 'Erick','email': 'erick#gmail.com'},
{'dependent': 'Ana','email':'ana#gmail.com'}]
I have tried many for loops inside another but it doesn't seem to work...

I suggest doing it in a couple of steps. First create a way to look up entries in b by supporterId:
>>> b_supporters = {d['supporterId']: d for d in b}
and then use that to build c:
>>> c = [d | b_supporters.get(d['supporterId'], {}) for d in a]
producing:
>>> c
[{'name': 'John', 'supporterId': 1}, {'name': 'Paul', 'supporterId': 2, 'dependent': 'Anna', 'email': 'ana#gmail.com'}]

I think this solves your problem:
c = []
for i, j in enumerate(a):
c.append(j)
c[i]['data'] = []
for k in b:
if j['supporterId'] == k['supporterId']:
c[i]['data'].append(k)
if not c[i]['data']:
del c[i]['data']
print(c)
Output:
[{'name': 'John', 'supporterId': 1}, {'name': 'Paul', 'supporterId': 2, 'data': [{'dependent': 'Erick', 'supporterId': 2, 'email': 'erick#gmail.com'}, {'dependent': 'Anna', 'supporterId': 2, 'email': 'ana#gmail.com'}]}]

Related

Having some problem adding list values ​in loop

My code:
a = {}
b = []
for i in range(1, 5):
a["Name"] = i
print(a)
b.append(a)
print(b)
result is [{'Name': 4}, {'Name': 4}, {'Name': 4}, {'Name': 4}]
how to make [{'Name': 1}, {'Name': 2}, {'Name': 3}, {'Name': 4}]
You are appending the same object over and over. The dictionary a only gets created once. You modify it on each loop iteration, but it's still the same dictionary, so you see the results of the last modification four times.
You want to generate a new dictionary on each loop iteration. Note there is no need to create an empty dictionary and then assign to a key. In this case we can simply use a dictionary literal with thatt key/value pair.
b = []
for i in range(1,5):
a = {'name': i}
print(a)
b.append(a)
print(b)
Or if you don't need print(a) you can do this more concisely with a list comprehension.
b = [{'name': i} for i in range(1, 5)]
print(b)
Just like #njzk2 said, you are modifying the same object.
b = []
for i in range(1, 5):
a = {}
a["Name"] = i
print(a)
b.append(a)
print(b)
This will fix it.
{'Name': 1}
{'Name': 2}
{'Name': 3}
{'Name': 4}
[{'Name': 1}, {'Name': 2}, {'Name': 3}, {'Name': 4}]

Concat 2 list of dictionaries with same id

I have 2 lists of dictionaries
a = [{'id':1, 'name':'John Doe'}, {'id':2, 'name':'Jane Doe'}, {'id':4, 'name':'Sample Doe'}]
b = [{'id':1, 'rating':9}, {'id':2, 'rating':7}, {'id':3, 'rating':8}]
Is there a way to concat b to a if the id b is on id a?
[{'id':1, 'name':'John Doe', 'rating':9}, {'id':2, 'name':'Jane Doe', 'rating':7}, {'id':4, 'name':'Sample Doe', 'rating':0}]
You could use the new merging dictionaries feature introduced in Python 3.9:
>>> a = [{'id': 1, 'name': 'John Doe'}, {'id': 2, 'name': 'Jane Doe'}, {'id': 4, 'name': 'Sample Doe'}]
>>> b = [{'id': 1, 'rating': 9}, {'id': 2, 'rating': 7}, {'id': 3, 'rating': 8}]
>>> b_id_to_d = {d['id']: d for d in b} # Create for O(1) lookup time by id.
>>> b_id_to_d
{1: {'id': 1, 'rating': 9}, 2: {'id': 2, 'rating': 7}, 3: {'id': 3, 'rating': 8}}
>>> c = [d | b_id_to_d.get(d['id'], {'rating': 0}) for d in a]
>>> c
[{'id': 1, 'name': 'John Doe', 'rating': 9}, {'id': 2, 'name': 'Jane Doe', 'rating': 7}, {'id': 4, 'name': 'Sample Doe', 'rating': 0}]
For older versions of Python you can try use dict unpacking instead:
>>> c = [{**d, **b_id_to_d.get(d['id'], {'rating': 0})} for d in a]
>>> c
[{'id': 1, 'name': 'John Doe', 'rating': 9}, {'id': 2, 'name': 'Jane Doe', 'rating': 7}, {'id': 4, 'name': 'Sample Doe', 'rating': 0}]
This should work:
[{**item1, **item2} for item1 in a for item2 in b if item1['id'] == item2['id']]
It iterates over the the two dict so it is O(n^2), but it is clear and concise.
{**item1, **item2} means adds the key value pairs from item1, then the key value pairs from item2.
Here, the results will be:
[{'id': 1, 'name': 'John Doe', 'rating': 9},
{'id': 2, 'name': 'Jane Doe', 'rating': 7}]
There is no direct solution to this problem.
But you can use following code:
a = [{'id':1, 'name':'John Doe'}, {'id':2, 'name':'Jane Doe'}]
b = [{'id':1, 'rating':9}, {'id':2, 'rating':7}, {'id':3, 'rating':8}]
key_pos_mapping = {}
for index,dict in enumerate(a):
key_pos_mapping[dict['id']] = index
for dict in b:
if( dict['id'] in key_pos_mapping.keys()):
dict.update(a[key_pos_mapping[dict['id']]])
else:
b.remove(dict)

Reuniting two dictionaries with key-value in common

I have two dictionaries and i want to compare them based on the supporterId key like so:
dict1 = [{'name': 'John', 'supporterId': 1}, {'name': 'Paul', 'supporterId': 2}]
dict2 = [{'dependent': 'Erick','supporterId': 2}, {'dependent': 'Anna', 'email': 'anna#gmail.com', 'supporterId': 2}, {'dependent': 'George','email': 'george#gmail.com',supporterId': 13}]
and I need to check if the supporterId between dict1 and dict2 are equal and if so put the name_dependent inside the corresponding supporterId in a so for example the output to this should be:
dict3 = {'name': 'Paul', 'supporterId': 2, 'dependent_name': ['George', 'Anna'], dependent_email: ['anna#gmail.com', 'george#gmail.com']}]

How to convert list of dict into two lists?

For example:
persons = [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'mary'}, {'id': 3, 'name': 'tom'}]
I want to get two lists from it:
ids = [1, 2, 3]
names = ['john', 'mary', 'tom']
What I did:
names = [d['name'] for d in persons]
ids = [d['id'] for d in persons]
Is there a better way to do it?
I'd stick with using list comprehension or use #Woodford technique
ids,name = [dcts['id'] for dcts in persons],[dcts['name'] for dcts in persons]
output
[1, 2, 3]
['john', 'mary', 'tom']
What you did works fine. Another way to handle this (not necessarily better, depending on your needs) is to store your data in a more efficient dictionary and pull the names/ids out of it when you need them:
>>> persons = [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'mary'}, {'id': 3, 'name': 'tom'}]
>>> p2 = {x['id']: x['name'] for x in persons}
>>> p2
{1: 'john', 2: 'mary', 3: 'tom'}
>>> list(p2.keys())
[1, 2, 3]
>>> list(p2.values())
['john', 'mary', 'tom']
You can do it with pandas in a vectorized fashion:
import pandas as pd
persons = [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'mary'}, {'id': 3, 'name': 'tom'}]
df = pd.DataFrame(persons)
id_list = df.id.tolist() #[1, 2, 3]
name_list = df.name.tolist() #['john', 'mary', 'tom']
An alternative, inspired by this question, is
ids, names = zip(*map(lambda x: x.values(), persons))
that return tuples. If you need lists
ids, names = map(list, zip(*map(lambda x: x.values(), persons)))
It is a little bit slower on my laptop using python3.9 than the accepted answer but it might be useful.
It sounds like you're trying to iterate through the values of your list while unpacking your dictionaries:
persons = [{'id': 1, 'name': 'john'}, {'id': 2, 'name': 'mary'}, {'id': 3, 'name': 'tom'}]
for x in persons:
id, name = x.values()
ids.append(id)
names.append(name)

How to reorder a list in Python based on its content

I have a list of dictionaries in python like this;
l = [{'name': 'John', 'age': 23},
{'name': 'Steve', 'age': 35},
{'name': 'Helen'},
{'name': 'George'},
{'name': 'Jessica', 'age': 23}]
What I am trying to achieve here is reorder the elements of l in such a way that each entry containing the key age move to the end of the list like this;
End result:
l = [{'name': 'Helen'},
{'name': 'George'},
{'name': 'Jessica', 'age': 23},
{'name': 'John', 'age': 23},
{'name': 'Steve', 'age': 35}]
How can I do this?
You can sort the list:
l.sort(key=lambda d: 'age' in d)
The key returns either True or False, based on the presence of the 'age' key; True is sorted after False. Python's sort is stable, leaving the rest of the relative ordering intact.
Demo:
>>> from pprint import pprint
>>> l = [{'name': 'John', 'age': 23},
... {'name': 'Steve', 'age': 35},
... {'name': 'Helen'},
... {'name': 'George'},
... {'name': 'Jessica', 'age': 23}]
>>> l.sort(key=lambda d: 'age' in d)
>>> pprint(l)
[{'name': 'Helen'},
{'name': 'George'},
{'age': 23, 'name': 'John'},
{'age': 35, 'name': 'Steve'},
{'age': 23, 'name': 'Jessica'}]
If you also wanted to sort by age, then retrieve the age value and return a suitable stable sentinel for those entries that do not have an age, but which will be sorted first. float('-inf') will always be sorted before any other number, for example:
l.sort(key=lambda d: d.get('age', float('-inf')))
Again, entries without an age are left in their original relative order:
>>> l.sort(key=lambda d: d.get('age', float('-inf')))
>>> pprint(l)
[{'name': 'Helen'},
{'name': 'George'},
{'age': 23, 'name': 'John'},
{'age': 23, 'name': 'Jessica'},
{'age': 35, 'name': 'Steve'}]

Categories