[Replace duplicate value - Python list] - python

Input:
data = [
{'name': 'A', 'value': 19, 'no': 1},
{'name': 'B', 'value': 5, 'no': 2},
{'name': 'A', 'value': 19, 'no': 3}
]
request_change_data = [
{'name': 'A', 'value': 35, 'no': 1},
{'name': 'B', 'value': 10, 'no': 2},
{'name': 'A', 'value': 40, 'no': 3}
]
expected_result:
data = [
{'name': 'A', 'value': 35, 'no': 1},
{'name': 'B', 'value': 10, 'no': 2},
{'name': 'A', 'value': 40, 'no': 3}
]
But actual:
[
{'name': 'A', 'value': 40, 'no': 1},
{'name': 'B', 'value': 10, 'no': 2},
{'name': 'A', 'value': 40, 'no': 3}
]
My code is:
data = [{'name': 'A', 'value': 19, 'no': 1}, {'name': 'B', 'value': 5, 'no': 2}, {'name': 'A', 'value': 19, 'no': 3}]
requests = [{'name': 'A', 'value': 35, 'no': 1}, {'name': 'B', 'value': 10, 'no': 2}, {'name': 'A', 'value': 40, 'no': 3}]
def test(data, requests):
for k, v in enumerate(data):
for request in requests:
if v['name'] == request['name']:
v['value'] =request['value']
return data
print(test(data, requests))
How could I change the duplicate stt1 vĂ  stt3. I used for to update the value of the key, it always updates only stt3 value is 40.
Please help. Thanks in advance

Each time you iterate through data, you then iterate over all of the request dictionaries, and your code only checks the name fields for each dictionary and then updates the value field in the dict from data if they match.
However, you have multiple dictionaries in requests with the same name, so if you were working the first data dict:
{'name': 'A', 'value': 19, 'no': 1}
You'd get this in for request in requests:
Iteration 1: request = {'name': 'A', 'value': 35, 'no': 1},
Iteration 2: request = {'name': 'B', 'value': 10, 'no': 2},
Iteration 3: request = {'name': 'A', 'value': 40, 'no': 3}
So you'd end up updating the data dict twice, first with v['value'] = 35 and then with v['value'] = 40.
So for your data, you want to check both name and no in the dicts and if they both match, then update the fields. Here's a fixed version of your code that does that:
data = [{'name': 'A', 'value': 19, 'no': 1}, {'name': 'B', 'value': 5, 'no': 2}, {'name': 'A', 'value': 19, 'no': 3}]
requests = [{'name': 'A', 'value': 35, 'no': 1}, {'name': 'B', 'value': 10, 'no': 2}, {'name': 'A', 'value': 40, 'no': 3}]
# You didn't seem to need the idx from enumerating so I removed it
# You also don't need to return data because lists/dicts are mutable
# types so you're modifying the actual dicts you pass in
def test(data, requests):
for d in data:
for request in requests:
if d['name'] == request['name'] and d['no'] == request['no']:
d['value'] = request['value']
test(data, requests)
print(data)
And I get this output, which is your expected:
[
{'name': 'A', 'value': 35, 'no': 1},
{'name': 'B', 'value': 10, 'no': 2},
{'name': 'A', 'value': 40, 'no': 3}
]

Related

change dict in pandas

I got this dictionary:
[{'id': 1, 'code': 'a'},
{'id': 2, 'code': 'b'},
{'id': 3, 'code': 'c'}]
and I want to change it to:
[{ 1: 'a'},
{2: 'b'},
{ 3: 'c'}]
(python pandas)
a = [{'id': 1, 'code': 'a'},
{'id': 2, 'code': 'b'},
{'id': 3, 'code': 'c'}]
b = []
for dic in a:
b.append({dic['id'] : dic['code']})
print(b)
>>[{1: 'a'}, {2: 'b'}, {3: 'c'}]
One option is with a dictionary comprehension:
[{ent['id']: ent['code']} for ent in a]
[{1: 'a'}, {2: 'b'}, {3: 'c'}]

How to convert a list of nested dictionaries (includes tuples) as a dataframe

I have a piece of code which generates a list of nested dictionaries like below:
[{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 2, 'num': 68}),
'final_value': 118},
{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 4, 'num': 67}),
'final_value': 117},
{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 6, 'num': 67}),
'final_value': 117}]
I want to convert the dictionary into a dataframe like below
How can I do it using Python?
I have tried the below piece of code
merge_values = [{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 2, 'num': 68}),
'final_value': 118},
{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 4, 'num': 67}),
'final_value': 117},
{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 6, 'num': 67}),
'final_value': 117}]
test = pd.DataFrame()
i = 0
for match in merge_values:
for d in match:
final_cfr = d['final_value']
comb = d['cb']
i = i+1
z = pd.DataFrame()
for t in comb:
dct = {k:[v] for k,v in t.items()}
x = pd.DataFrame(dct)
x['merge_id'] = i
x['Final_Value'] = final_value
test = pd.concat([test, x])
The problem with this piece of code is it adds the rows one below another. I need the elements of the tuple next to each other.
You will need to clean your data by creating a new dict with the structure that you want, like this:
import pandas as pd
dirty_data = [{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 2, 'num': 68}),
'final_value': 118},
{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 4, 'num': 67}),
'final_value': 117},
{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 6, 'num': 67}),
'final_value': 117}]
def clean_data(dirty_data: dict) -> dict:
names = []
ids = []
nums = []
m_ids = []
m_nums = []
finals = []
for cb in dirty_data:
names.append(cb["cb"][0]["Name"])
ids.append(cb["cb"][0]["ID"])
nums.append(cb["cb"][0]["num"])
m_ids.append(cb["cb"][1]["ID"])
m_nums.append(cb["cb"][1]["num"])
finals.append(cb["final_value"])
return {"Name": names, "ID": ids, "num": nums, "M_ID": m_ids, "M_num": m_nums, "Final": finals}
df = pd.DataFrame(clean_data(dirty_data))
df
You could try to read the data into a dataframe as is and then restructure it until you get the desired result, but in this case, it doesn't seem practical.
Instead, I'd flatten the input into a list of lists to pass to pd.DataFrame. Here is a relatively concise way to do that with your sample data:
from operator import itemgetter
import pandas as pd
data = [{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 2, 'num': 68}),
'final_value': 118},
{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 4, 'num': 67}),
'final_value': 117},
{'cb': ({'Name': 'A', 'ID': 1, 'num': 50},
{'Name': 'A', 'ID': 6, 'num': 67}),
'final_value': 117}]
keys = ['Name', 'ID', 'num', 'M_Name', 'M_ID', 'M_num', 'final_value']
# generates ['A', 1, 50, 'A', 2, 68, 118] etc.
flattened = ([value for item in row['cb']
for value in itemgetter(*keys[:3])(item)]
+ [row['final_value']]
for row in data)
df = pd.DataFrame(flattened)
df.columns = keys
# get rid of superfluous M_Name column
df.drop('M_Name', axis=1, inplace=True)
itemgetter(*keys[:3])(item) is the same as [item[k] for k in keys[:3]]. On flattening lists of lists with list (or generator) comprehensions, see How do I make a flat list out of a list of lists?.
Result:
Name ID num M_ID M_num final_value
0 A 1 50 2 68 118
1 A 1 50 4 67 117
2 A 1 50 6 67 117

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)

In List of dicts, find dicts with most values [duplicate]

This question already has answers here:
Top-k on a list of dict in python
(3 answers)
Closed 2 years ago.
I have a list of python dicts like this:
[{'name': 'A', 'score': 12},
{'name': 'B', 'score': 20},
{'name': 'C', 'score': 11},
{'name': 'D', 'score': 20},
{'name': 'E', 'score': 9}]
How do I select first three dicts with highest score values? [D, B, A]
Sort using the score as a key, then take the top 3 elements:
>>> sorted([{'name': 'A', 'score': 12},
... {'name': 'B', 'score': 20},
... {'name': 'C', 'score': 11},
... {'name': 'D', 'score': 20},
... {'name': 'E', 'score': 9}], key=lambda d: d['score'])[-3:]
[{'name': 'A', 'score': 12}, {'name': 'B', 'score': 20}, {'name': 'D', 'score': 20}]

Combining multiple lists of dictionaries

I have several lists of dictionaries, where each dictionary contains a unique id value that is common among all lists. I'd like to combine them into a single list of dicts, where each dict is joined on that id value.
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
desired_output = [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
I tried doing something like the answer found at https://stackoverflow.com/a/42018660/7564393, but I'm getting very confused since I have more than 2 lists. Should I try using a defaultdict approach? More importantly, I am NOT always going to know the other values, only that the id value is present in all dicts.
You can use itertools.groupby():
from itertools import groupby
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
desired_output = []
for _, values in groupby(sorted([*list1, *list2, *list3], key=lambda x: x['id']), key=lambda x: x['id']):
temp = {}
for d in values:
temp.update(d)
desired_output.append(temp)
Result:
[{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
# combine all lists
d = {} # id -> dict
for l in [list1, list2, list3]:
for list_d in l:
if 'id' not in list_d: continue
id = list_d['id']
if id not in d:
d[id] = list_d
else:
d[id].update(list_d)
# dicts with same id are grouped together since id is used as key
res = [v for v in d.values()]
print(res)
You can first build a dict of dicts, then turn it into a list:
from itertools import chain
from collections import defaultdict
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
dict_out = defaultdict(dict)
for d in chain(list1, list2, list3):
dict_out[d['id']].update(d)
out = list(dict_out.values())
print(out)
# [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
itertools.chain allows you to iterate on all the dicts contained in the 3 lists. We build a dict dict_out having the id as key, and the corresponding dict being built as value. This way, we can easily update the already built part with the small dict of our current iteration.
Here, I have presented a functional approach without using itertools (which is excellent in rapid development work).
This solution will work for any number of lists as the function takes variable number of arguments and also let user to specify the type of return output (list/dict).
By default it returns list as you want that otherwise it returns dictionary in case if you pass as_list = False.
I preferred dictionary to solve this because its fast and search complexity is also less.
Just have a look at the below get_packed_list() function.
get_packed_list()
def get_packed_list(*dicts_lists, as_list=True):
output = {}
for dicts_list in dicts_lists:
for dictionary in dicts_list:
_id = dictionary.pop("id") # id() is in-built function so preferred _id
if _id not in output:
# Create new id
output[_id] = {"id": _id}
for key in dictionary:
output[_id][key] = dictionary[key]
dictionary["id"] = _id # push back the 'id' after work (call by reference mechanism)
if as_list:
return [output[key] for key in output]
return output # dictionary
Test
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
output = get_packed_list(list1, list2, list3)
print(output)
# [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]
output = get_packed_list(list1, list2, list3, as_list=False)
print(output)
# {1: {'id': 1, 'value': 20, 'sum': 10, 'total': 30}, 2: {'id': 2, 'value': 21, 'sum': 11, 'total': 32}}
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
print(list1+list2+list3)
list1 = [{'id': 1, 'value': 20}, {'id': 2, 'value': 21}]
list2 = [{'id': 1, 'sum': 10}, {'id': 2, 'sum': 11}]
list3 = [{'id': 1, 'total': 30}, {'id': 2, 'total': 32}]
result = []
for i in range(0,len(list1)):
final_dict = dict(list(list1[i].items()) + list(list2[i].items()) + list(list3[i].items()))
result.append(final_dict)
print(result)
output : [{'id': 1, 'value': 20, 'sum': 10, 'total': 30}, {'id': 2, 'value': 21, 'sum': 11, 'total': 32}]

Categories