asd-qwert
asd-qwert

Reputation: 39

Is there a way to group values in python dictionaries and list?

I currently have a list of values which look something like this:

lst = [{'Amount': 13.5, 'Name': 'Amy', 'date': '2022-01-30'}, 
{'Amount': 15, 'Name': 'Bob', 'date': '2022-01-30'}, 
{'Amount': 13.5, 'Name': 'Cara', 'date': '2022-01-31'}]

How can I group it by the date?

[{'date': '2022-01-30', 'details': [{'Amount': 13.5, 'Name': 'Amy'}, {'Amount': 15, 'Name': 'Bob'}]},
{'date': '2022-01-31', 'details': [{'Amount': 13.5, 'Name': 'Cara'}]

I have tried something with for loop but it doesnt seem to work for me

final_data = []

for i in lst:
    temp_data = {}
    if i['date'] not in temp_data:
        temp_data['date'] = i['date']
        final_data.append(temp_data)

Upvotes: 0

Views: 59

Answers (2)

hc_dev
hc_dev

Reputation: 9377

The self-implementing way is using for-loop with adding to the desired structure.

You can also use the module from standard library itertools.groupby, when the input is sorted (before).

Group by

You can adjust the example from docs for your case:

from itertools import groupby

lst = [
   {'Amount': 13.5, 'Name': 'Amy', 'date': '2022-01-30'}, 
   {'Amount': 15, 'Name': 'Bob', 'date': '2022-01-30'}, 
   {'Amount': 13.5, 'Name': 'Cara', 'date': '2022-01-31'}
]
keyfunc = lambda x: x['date']  # extracting the key for sort and group

groups = []
uniquekeys = []

data = sorted(lst, key=keyfunc)  # required for groupby
for k, g in groupby(data, keyfunc):
    groups.append({'date': k, 'details': list(g)})  # Store group iterator as a list
    uniquekeys.append(k)

print(groups)

Prints:

[{'date': '2022-01-30', 'details': [{'Amount': 13.5, 'Name': 'Amy', 'date': '2022-01-30'}, {'Amount': 15, 'Name': 'Bob', 'date': '2022-01-30'}]}, {'date': '2022-01-31', 'details': [{'Amount': 13.5, 'Name': 'Cara', 'date': '2022-01-31'}]}]

Remove the key

Since your output in details is not just a grouped list, but has the key (used for group-by) removed, we need to adjust a bit:

from itertools import groupby

lst = [
   {'Amount': 13.5, 'Name': 'Amy', 'date': '2022-01-30'}, 
   {'Amount': 15, 'Name': 'Bob', 'date': '2022-01-30'}, 
   {'Amount': 13.5, 'Name': 'Cara', 'date': '2022-01-31'}
]
keyfunc = lambda x: x['date']  # extracting the key for sort and group

groups = []

data = sorted(lst, key=keyfunc)  # required for groupby
for k, g in groupby(data, keyfunc):
    # remove the key from grouped list
    removed_key = []
    for v in list(g):
        del v['date']
        removed_key.append(v)
    # add to groups  
    groups.append({'date': k, 'details': removed_key})

print(groups)

Prints desired:

[{'date': '2022-01-30', 'details': [{'Amount': 13.5, 'Name': 'Amy'}, {'Amount': 15, 'Name': 'Bob'}]}, {'date': '2022-01-31', 'details': [{'Amount': 13.5, 'Name': 'Cara'}]}]

Upvotes: 0

mozway
mozway

Reputation: 260380

I would recommend to use a dictionary as output:

from collections import defaultdict
out = defaultdict(list)

for d in lst:
    d = d.copy() # avoids mutating the original dictionaries.
    out[d.pop('date')].append(d)

dict(out)

output:

{'2022-01-30': [{'Amount': 13.5, 'Name': 'Amy'}, {'Amount': 15, 'Name': 'Bob'}],
'2022-01-31': [{'Amount': 13.5, 'Name': 'Cara'}]}

If you really want your format:

out2 = [{'date': k, 'details': v} for k,v in out.items()]

output:

[{'date': '2022-01-30', 'details': [{'Amount': 13.5, 'Name': 'Amy'}, {'Amount': 15, 'Name': 'Bob'}]},
 {'date': '2022-01-31', 'details': [{'Amount': 13.5, 'Name': 'Cara'}]}]
first part without defaultdict:
out = {}

for d in lst:
    d = d.copy()
    date = d.pop('date')
    if date not in out:
        out[date] = []
    out[date].append(d)
both parts in one shot:
out = {}

for d in lst:
    d = d.copy()
    date = d.pop('date')
    if date not in out:
        out[date] = {'date': date, 'details': []}
    out[date]['details'].append(d)

out = list(out.values())

Upvotes: 1

Related Questions