Python get max and min from list of dicts - python

how can I get the max and min value from code like this:
[{'sum': 44, 'code': 'A'},
{'sum': 1, 'code': 'B'},
{'sum': 44, 'code': 'B'},
{'sum': 33, 'code': 'B'},
{'sum': 2, 'code': 'C'},
{'sum': 694, 'code': 'A'},
{'sum': 12, 'code': 'B'},
{'sum': 5, 'code': 'C'}]
And i need results like this:
#max
[{'sum': 694, 'code': 'A'},
{'sum': 44, 'code': 'B'},
{'sum': 5, 'code': 'C'}]
#min
[{'sum': 44, 'code': 'A'},
{'sum': 1, 'code': 'B'},
{'sum': 2, 'code': 'C'}]

You can use itertools.groupby cf. How do I use Python's itertools.groupby()? for details, and max's key argument. This makes for a short code:
from itertools import groupby
input = [
{'sum': 44, 'code': 'A'},
{'sum': 1, 'code': 'B'},
{'sum': 44, 'code': 'B'},
{'sum': 33, 'code': 'B'},
{'sum': 2, 'code': 'C'},
{'sum': 694, 'code': 'A'},
{'sum': 12, 'code': 'B'},
{'sum': 5, 'code': 'C'}
]
# groupby requires its input to be sorted by group key
input.sort(key=lambda x: (x['code'], x['sum'])
maximums = list()
minimums = list()
for code, group in groupby(input, key=lambda x: x['code']):
group = list(group) # Consume iterator
maximums.append(group[-1])
minimums.append(group[0])
print 'max:', maximums
print 'min:', minimums
This will get you:
max: [{'sum': 694, 'code': 'A'}, {'sum': 44, 'code': 'B'}, {'sum': 5, 'code': 'C'}]
min: [{'sum': 44, 'code': 'A'}, {'sum': 1, 'code': 'B'}, {'sum': 2, 'code': 'C'}]

from operator import itemgetter
from itertools import groupby
sorted1 = sorted(my_list,key=itemgetter("code","sum"))
#the line above is where the magic happens it sorts the list first on code and then on sum, this leads it to be grouped by code and within each group the results are sorted
maxes = []
mins = []
for code,results in groupby(sorted1,itemgetter("code"))
results = list(results)
maxes.append(results[-1])
mins.append(results[0])

you could use a custom comparison key:
max(my_list, key=lambda my_dict: my_dict.keys()[0])

You can set up dictionaries to hold the max and min values. Then loop through each dictionary item in your list and compare against the max and min values and update if required. Also, insert new codes into the max/min dictionaries.
max_ = {}
min_ = {}
for item in lst:
code, val = item['code'], item['sum']
if code not in max_ or val > max_[code]:
max_[code] = val
if code not in min_ or val < min_[code]:
min_[code] = val
>>> max_
{'A': 694, 'B': 44, 'C': 5}
>>>min_
{'A': 44, 'B': 1, 'C': 2}
If you need your specified format, this can be easily recovered as follows:
[{'code': code, 'sum': val} for code, val in max_.iteritems()]
# Max
[{'code': 'A', 'sum': 694}, {'code': 'C', 'sum': 5}, {'code': 'B', 'sum': 44}]

def get_max(lst):
dict = {}
for el in lst:
code = el['code']
sum = el['sum']
if code in dict:
if dict[code] < sum:
dict[code] = sum
else:
dict[code] = sum
return dict
def get_min(lst):
dict = {}
for el in lst:
code = el['code']
sum = el['sum']
if code in dict:
if dict[code] > sum:
dict[code] = sum
else:
dict[code] = sum
return dict
this will get you:
{'A': 694, 'C': 5, 'B': 44}
{'A': 44, 'C': 2, 'B': 1}

Mandatory one-liner:
[max((v for v in vals if v['code'] == x), key=lambda y:y['sum']) for x in set(v['code'] for v in vals)]
>>> [{'sum': 694, 'code': 'A'}, {'sum': 5, 'code': 'C'}, {'sum': 44, 'code': 'B'}]
Details:
set(v['code'] for v in vals) gets the unique codes
v for v in vals if v['code'] == x filters the values based on code == x
max(..., key=lambda y:y['sum']) give you the max value of that based on the sum field
Now, creating the set of codes, and then re-filtering based on that is not very efficient, the group_by method is cleaner.

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'}]

[Replace duplicate value - Python list]

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}
]

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)

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}]

Order by value in dictionary

I'm just practising with python. I have a dictionary in the form:
my_dict = [{'word': 'aa', 'value': 2},
{'word': 'aah', 'value': 6},
{'word': 'aahed', 'value': 9}]
How would I go about ordering this dictionary such that if I had thousands of words I would then be able to select the top 100 based on their value ranking? e.g., from just the above example:
scrabble_rank = [{'word': 'aahed', 'rank': 1},
{'word': 'aah', 'rank': 2},
{'word': 'aa', 'rank': 3}]
Firstly, that's not a dictionary; it's a list of dictionaries. Which is good, because dictionaries are unordered, but lists are ordered.
You can sort the list by the value of the rank element by using it as a key to the sort function:
scrabble_rank.sort(key=lambda x: x['value'])
Is this what you are looking for:
scrabble_rank = [{'word':it[1], 'rank':idx+1} for idx,it in enumerate(sorted([[item['value'],item['word']] for item in my_dict],reverse=True))]
Using Pandas Library:
import pandas as pd
There is this one-liner:
scrabble_rank = pd.DataFrame(my_dict).sort_values('value', ascending=False).reset_index(drop=True).reset_index().to_dict(orient='records')
It outputs:
[{'index': 0, 'value': 9, 'word': 'aahed'},
{'index': 1, 'value': 6, 'word': 'aah'},
{'index': 2, 'value': 2, 'word': 'aa'}]
Basically it reads your records into a DataFrame, then it sort by value in descending order, then it drops original index (order), and it exports as records (your previous format).
You can use heapq:
import heapq
my_dict = [{'word': 'aa', 'value': 2},
{'word': 'aah', 'value': 6},
{'word': 'aahed', 'value': 9}]
# Select the top 3 records based on `value`
values_sorted = heapq.nlargest(3, # fetch top 3
my_dict, # dict to be used
key=lambda x: x['value']) # Key definition
print(values_sorted)
[{'word': 'aahed', 'value': 9}, {'word': 'aah', 'value': 6}, {'word': 'aa', 'value': 2}]

Categories