Concat 2 list of dictionaries with same id - python

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)

Related

Comparing key-value from two dictionaries 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'}]}]

maintain dictionary structure while reducing nested dictionary

I have a list of pairs of nested dict dd and would like to maintain the structure to a list of dictionaries:
dd = [
[{'id': 'bla',
'detail': [{'name': 'discard', 'amount': '123'},
{'name': 'KEEP_PAIR_1A', 'amount': '2'}]},
{'id': 'bla2',
'detail': [{'name': 'discard', 'amount': '123'},
{'name': 'KEEP_PAIR_1B', 'amount': '1'}]}
],
[{'id': 'bla3',
'detail': [{'name': 'discard', 'amount': '123'},
{'name': 'KEEP_PAIR_2A', 'amount': '3'}]},
{'id': 'bla4',
'detail': [{'name': 'discard', 'amount': '123'},
{'name': 'KEEP_PAIR_2B', 'amount': '4'}]}
]
]
I want to reduce this to a list of paired dictionaries while extracting only some detail. For example, an expected output may look like this:
[{'name': ['KEEP_PAIR_1A', 'KEEP_PAIR_1B'], 'amount': [2, 1]},
{'name': ['KEEP_PAIR_2A', 'KEEP_PAIR_2B'], 'amount': [3, 4]}]
I have run my code:
pair=[]
for all_pairs in dd:
for output_pairs in all_pairs:
for d in output_pairs.get('detail'):
if d['name'] != 'discard':
pair.append(d)
output_pair = {
k: [d.get(k) for d in pair]
for k in set().union(*pair)
}
But it didn't maintain that structure :
{'name': ['KEEP_PAIR_1A', 'KEEP_PAIR_1B', 'KEEP_PAIR_2A', 'KEEP_PAIR_2B'],
'amount': ['2', '1', '3', '4']}
I assume I would need to use some list comprehension to solve this but where in the for loop should I do that to maintain the structure.
Since you want to combine dictionaries in lists, one option is to use dict.setdefault:
pair = []
for all_pairs in dd:
dct = {}
for output_pairs in all_pairs:
for d in output_pairs.get('detail'):
if d['name'] != 'discard':
for k,v in d.items():
dct.setdefault(k, []).append(v)
pair.append(dct)
Output:
[{'name': ['KEEP_PAIR_1A', 'KEEP_PAIR_1B'], 'amount': [2, 1]},
{'name': ['KEEP_PAIR_2A', 'KEEP_PAIR_2B'], 'amount': [3, 4]}]

How to convert key to value in dictionary type?

I have a question about the convert key.
First, I have this type of word count in Data Frame.
[Example]
dict = {'forest': 10, 'station': 3, 'office': 7, 'park': 2}
I want to get this result.
[Result]
result = {'name': 'forest', 'value': 10,
'name': 'station', 'value': 3,
'name': 'office', 'value': 7,
'name': 'park', 'value': 2}
Please check this issue.
As Rakesh said:
dict cannot have duplicate keys
The closest way to achieve what you want is to build something like that
my_dict = {'forest': 10, 'station': 3, 'office': 7, 'park': 2}
result = list(map(lambda x: {'name': x[0], 'value': x[1]}, my_dict.items()))
You will get
result = [
{'name': 'forest', 'value': 10},
{'name': 'station', 'value': 3},
{'name': 'office', 'value': 7},
{'name': 'park', 'value': 2},
]
As Rakesh said, You can't have duplicate values in the dictionary
You can simply try this.
dict = {'forest': 10, 'station': 3, 'office': 7, 'park': 2}
result = {}
count = 0;
for key in dict:
result[count] = {'name':key, 'value': dict[key]}
count = count + 1;
print(result)

how to add list values to existing dictionary in python

Im trying to add each values of score to the dict names i,e score[0] to names[0] and so on...
names=[{'id': 1, 'name': 'laptop'}, {'id': 2, 'name': 'box'}, {'id': 3, 'name': 'printer'}]
score = [0.9894376397132874, 0.819094657897949, 0.78116521835327]
Output should be like this
names=[{'id': 1, 'name': 'laptop','score':0.98}, {'id': 2, 'name': 'box','score':0.81}, {'id': 3, 'name': 'printer','score':0.78}]
How to achieve this? thanks in advance
I'd do it with a comprehension like this:
>>> [{**d, 'score':s} for d, s in zip(names, score)]
[{'id': 1, 'name': 'laptop', 'score': 0.9894376397132874}, {'id': 2, 'name': 'box', 'score': 0.819094657897949}, {'id': 3, 'name': 'printer', 'score': 0.78116521835327}]
Without list comprehension.
for i, name in enumerate(names):
name['score'] = score[i]
print(names)
This is an easy-to-understand solution. From your example, I understand you don't want to round up the numbers but still want to cut them.
import math
def truncate(f, n):
return math.floor(f * 10 ** n) / 10 ** n
names=[{'id': 1, 'name': 'laptop'}, {'id': 2, 'name': 'box'}, {'id': 3, 'name': 'printer'}]
score = [0.9894376397132874, 0.819094657897949, 0.78116521835327]
n = len(score)
for i in range(n):
names[i]["score"] = truncate(score[i], 2)
print(names)
If you do want to round up the numbers:
names=[{'id': 1, 'name': 'laptop'}, {'id': 2, 'name': 'box'}, {'id': 3, 'name': 'printer'}]
score = [0.9894376397132874, 0.819094657897949, 0.78116521835327]
n = len(score)
for i in range(n):
names[i]["score"] = round(score[i], 2)
print(names)

Remove duplicates from list of dictionaries within list of dictionaries

I have list:
my_list = [{'date': '10.06.2016',
'account': [{'name': 'a'},
{'name': 'a'},
{'name': 'b'},
{'name': 'b'}]},
{'date': '22.06.2016',
'account': [{'name': 'a'},
{'name': 'a'}]}]
I want to remove duplicates from the list of dictionaries in 'account':
my_list = [{'date': '10.06.2016',
'account': [{'name': 'a'},
{'name': 'b'}]},
{'date': '22.06.2016',
'account': [{'name': 'a'}]}]
When using set, I get the following error:
TypeError: unhashable type: 'dict'
Can anybody help me with this problem?
This structure is probably over complicated, but it gets the job done.
my_list = [{'date': '10.06.2016',
'account': [{'name': 'a'},
{'name': 'a'},
{'name': 'b'},
{'name': 'b'}]},
{'date': '22.06.2016',
'account': [{'name': 'a'},
{'name': 'a'}]}]
>>> [{'date': date,
'account': [{'name': name} for name in group]
} for group, date in zip([set(account.get('name')
for account in item.get('account'))
for item in my_list],
[d.get('date') for d in my_list])]
[{'account': [{'name': 'a'}, {'name': 'b'}], 'date': '10.06.2016'},
{'account': [{'name': 'a'}], 'date': '22.06.2016'}]
def deduplicate_account_names(l):
for d in l:
names = set(map(lambda d: d.get('name'), d['account']))
d['account'] = [{'name': name} for name in names]
# even shorter:
# def deduplicate_account_names(l):
# for d in l:
# d['account'] = [{'name': name} for name in set(map(lambda d: d.get('name'), d['account']))]
my_list = [{'date': '10.06.2016',
'account': [{'name': 'a'},
{'name': 'a'},
{'name': 'b'},
{'name': 'b'}]},
{'date': '22.06.2016',
'account': [{'name': 'a'},
{'name': 'a'}]}]
deduplicate_account_names(my_list)
print(my_list)
# [ {'date': '10.06.2016',
# 'account': [ {'name': 'a'},
# {'name': 'b'} ] },
# {'date': '22.06.2016',
# 'account': [ {'name': 'a'} ] } ]
Sets can only have hashable members and neither lists nor dicts are - but they can be checked for equality.
you can do
def without_duplicates(inlist):
outlist=[]
for e in inlist:
if e not in outlist:
outlist.append(e)
return outlist
this can be slow for really big lists
Give this code a try:
for d in my_list:
for k in d:
if k == 'account':
v = []
for d2 in d[k]:
if d2 not in v:
v.append(d2)
d[k] = v
This is what you get after running the snippet above:
In [347]: my_list
Out[347]:
[{'account': [{'name': 'a'}, {'name': 'b'}], 'date': '10.06.2016'},
{'account': [{'name': 'a'}], 'date': '22.06.2016'}]

Categories