1

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'}]
Thomas Jerkson
  • 229
  • 1
  • 2
  • 7

6 Answers6

4

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'}]
Community
  • 1
  • 1
amirouche
  • 7,682
  • 6
  • 40
  • 94
  • 1
    you should just `.sort(key=lambda x:(x["code"],x["sum"]))` that way your groups are all sorted and you dont have to call max and min when you are appending :P – Joran Beasley Sep 10 '15 at 17:20
  • 1
    in a single line that would look like: `[list(group)[-1] for _, group in groupby(sorted(input, key=lambda x: (x['code'], x['sum'])), key=lambda x: x['code'])]` – njzk2 Sep 10 '15 at 18:57
  • I would advise against naming variables `input`. you are shadowing a function – njzk2 Sep 10 '15 at 18:58
2
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])
Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
1

you could use a custom comparison key:

max(my_list, key=lambda my_dict: my_dict.keys()[0])
Lawrence Benson
  • 1,398
  • 1
  • 16
  • 33
1

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}]
Alexander
  • 105,104
  • 32
  • 201
  • 196
0
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}

taesu
  • 4,482
  • 4
  • 23
  • 41
0

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.

njzk2
  • 38,969
  • 7
  • 69
  • 107