Jamgreen
Jamgreen

Reputation: 11039

Group list by some value in Python

I have a list with dates and each dict in the list has another list:

list = [
  {
    'date': 'X',
    'tickets': [
      { 'price': 100 },
      { 'price': 120 },
      { 'price': 100 },
      { 'price': 100 },
    ]
  },
  {
    'date': 'Y',
    'tickets': [
      { 'price': 300 },
      { 'price': 300 },
      { 'price': 100 },
      { 'price': 100 },
    ]
  }
]

Right now I am looping through the dates with

print('Date, Number of Tickets')
print('============')

for element in list:
  print(element.date + ' - ' + len(element.tickets))

which prints

Date, Number of Tickets
============
X - 4
Y - 4

but what I want it to print is

Date, Number of Tickets, Price
============
X - 3 - 100
X - 1 - 120
Y - 2 - 300
Y - 2 - 100

So I need it to group the list of tickets and loop through each group.

So it might be something like

print('Date, Number of Tickets, Price')
print('============')

for element in list:
  groups = group_by(element.tickets, 'price')

  for group in groups:
    print(element.date + ' - ' + group.num_tickets + ' - ' + group.price)

but I don't know how to group the tickets by price. Also, if there are no tickets for the date (i.e., tickets = []), then I still need a row saying with date=?, num_tickets=0, and price=None.

Upvotes: 0

Views: 1603

Answers (3)

cs95
cs95

Reputation: 402493

I believe you're looking for itertools.groupby. In order for this to work, you'll need to sort the price items first.

import itertools

list_ = ...

for element in list_:
    groups = [list(g) for _, g in itertools.groupby(sorted(element['tickets'], key=lambda x: x['price']))]

    if groups:
        for group in groups:
            print(element['date'], len(group), group[0]['price'], sep=' - ')
    else:
        print(element['date'], 0, None, sep=' - ')

Output:

X - 3 - 100
X - 1 - 120
Y - 2 - 100
Y - 2 - 300

Don't name a list as list, or a dict as dict, or any other builtin name.


Now, setting list_[1]['tickets'] = []...

X - 3 - 100
X - 1 - 120
Y - 0 - None

Upvotes: 0

Chikiro
Chikiro

Reputation: 264

First: iterate all prices to create list, then sort it. Second: feed sorted list of prices to Counter. Then combine it in list of dictionaries with date.

from collections import Counter

data = <data with ticket prices here>

tickets = [{'date': x['date'], 'tickets_by_price': Counter(sorted([y['price'] for y in x['tickets']]))} for x in data]

Result:

[
    {
        'tickets_by_price': Counter({100: 3, 120: 1}), 
        'date': 'x'
    },
    {
        'tickets_by_price': Counter({300: 2, 100: 2}),
        'date': 'y'
    }
 ]

Upvotes: 0

Jon Clements
Jon Clements

Reputation: 142156

Loop over your data and accumulate the ticket prices into a collections.Counter then print out the results, eg:

from collections import Counter

for item in data:
    if not item['tickets']:
        print(item['date'], 0, 'None', sep=' - ')
        continue
    for price, count in Counter(el['price'] for el in item['tickets']).items():
        print(item['date'], count, price, sep=' - ')

Gives you:

X - 1 - 120
X - 3 - 100
Y - 2 - 100
Y - 2 - 300

Upvotes: 1

Related Questions