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}]
Related
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
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}
]
What I have:
a=[{'name':'a','vals':1,'required':'yes'},{'name':'b','vals':2},{'name':'d','vals':3}]
b=[{'name':'a','type':'car'},{'name':'b','type':'bike'},{'name':'c','type':'van'}]
What I tried:
[[i]+[j] for i in b for j in a if i['name']==j['name']]
What I got:
[[{'name': 'a', 'type': 'car'}, {'name': 'a', 'vals': 1}], [{'name': 'b', 'type': 'bike'}, {'name': 'b', 'vals': 2}]]
What I want:
[{'name': 'a', 'type': 'car','vals': 1},{'name': 'b', 'type': 'bike','vals': 2}]
Note:
I need to merge dicts into one dict.
It should merge only those have common 'name' in both a and b.
I want python one liner answer.
For Python 3, you can do this:
a=[{'name':'a','vals':1},{'name':'b','vals':2},{'name':'d','vals':3}]
b=[{'name':'a','type':'car'},{'name':'b','type':'bike'},{'name':'c','type':'van'}]
print([{**i,**j} for i in b for j in a if i['name']==j['name']])
mydict = {'a': {'name': 'Marco', 'gender': 'm', 'age': 38, 'info': 'teacher musician'}
'b': {'name': 'Daniela', 'gender': 'f', 'age': 28, 'info': 'student music'}
'c': {'name': 'Maria', 'gender': 'f', 'age': 25, 'info': 'doctor dance whatever'}}
How to select the records with an age below 30 and with the words including 'music' in the 'info'?
The results should be like:
newdict = {'b': {'name': 'Daniela', 'gender': 'f', 'age': 28, 'info': 'student music'}}
Simplest way is to use a dict-comp:
mydict = {'a': {'name': 'Marco', 'gender': 'm', 'age': 38, 'info': 'teacher musician'},
'b': {'name': 'Daniela', 'gender': 'f', 'age': 28, 'info': 'student music'},
'c': {'name': 'Maria', 'gender': 'f', 'age': 25, 'info': 'doctor dance whatever'}}
new_dict = {k:v for k,v in mydict.iteritems() if v['age'] < 30 and 'music' in v['info'].split()}
# {'b': {'info': 'student music', 'gender': 'f', 'age': 28, 'name': 'Daniela'}}
You can use the following comprehension :
>>> {d:k for d,k in mydict.items() if k['age']<30 and 'music' in k['info']}
{'b': {'info': 'student music', 'gender': 'f', 'age': 28, 'name': 'Daniela'}}
mydict.items() give you a tuple contain key ans value of dictionary at each loop , and you can chose the item that have the proper conditions !
In a list containing dictionaries, how do I split it based on unique values of dictionaries? So for instance, this:
t = [
{'name': 'xyz', 'value': ['K','L', 'M', 'N']},
{'name': 'abc', 'value': ['O', 'P', 'K']}
]
becomes this:
t = [
{'name': 'xyz', 'value': 'K'},
{'name': 'xyz', 'value': 'L'},
{'name': 'xyz', 'value': 'M'},
{'name': 'xyz', 'value': 'N'},
{'name': 'abc', 'value': 'O'},
{'name': 'xyz', 'value': 'P'},
{'name': 'xyz', 'value': 'K'}
]
You can do this with a list comprehension. Iterate through each dictionary d, and create a new dictionary for each value in d['values']:
>>> t = [ dict(name=d['name'], value=v) for d in t for v in d['value'] ]
>>> t
[{'name': 'xyz', 'value': 'K'},
{'name': 'xyz', 'value': 'L'},
{'name': 'xyz', 'value': 'M'},
{'name': 'xyz', 'value': 'N'},
{'name': 'abc', 'value': 'O'},
{'name': 'abc', 'value': 'P'},
{'name': 'abc', 'value': 'K'}]