Группировать список по полю, которое, в свою очередь, является списком

У меня есть класс для фильмов:

class Movie:
    def __init__(self,
                 title: str,
                 director: str,
                 actors: list[str]):
        self.title = title
        self.director = director
        self.actors: list[str] = actors

И список с 3 примерами фильмов:

movies = [Movie('Barton Fink', 'Joel Coen', ['John Turturro', 'John Goodman', 'Judy Davis']),
          Movie('The Big Lebowski', 'Joel Coen', ['Jeff Bridges', 'John Goodman', 'Steve Buscemi', 'John Turturro']),
          Movie('The Big Easy', 'Jim McBride', ['Dennis Quaid', 'Ellen Barkin', 'John Goodman']),
         ]

Я использую Pandas, чтобы получить количество вхождений всех актеров:

John Goodman: 3
John Turturro: 2
Judy Davis: 1
...

Для режиссеров это работает так:

df = DataFrame([vars(m) for m in movies])
grouped = df.groupby(['director']).size().sort_values(ascending=False)
print(df)

Но для актеров нет:

df = DataFrame([vars(m) for m in movies])
grouped = df.groupby(['actors']).size().sort_values(ascending=False)
print(df)

Это не работает, потому что в отличие от пользовательских классов (по умолчанию) или кортежей, списки не хэшируются:

Ошибка: (<класс «TypeError»>, TypeError («нехешируемый тип: «список»»), <объект трассировки по адресу 0x00000274C91E4340>)

Как сгруппировать по списку актеров?

🤔 А знаете ли вы, что...
Python поддерживает множество парадигм программирования, включая процедурное, объектно-ориентированное и функциональное программирование.


117
2

Ответы:

Решено

Для этого вам не нужны панды. Вы можете использовать collections.Counter.

from collections import Counter

Counter(actor for movie in movies for actor in movie.actors)

Здесь мы видим пример проблемы XY. Я уверен, что первоначальная цель заключалась не в группировке по спискам, а в подсчете количества фильмов для каждого актера, поскольку ожидаемый результат выглядит следующим образом:

John Goodman: 3
John Turturro: 2
Judy Davis: 1
...

В Pandas мы можем сделать это с помощью value_counts и взрыв:

director_occurrences = df['director'].value_counts()
actor_occurences = df['actors'].explode().value_counts()

print(director_occurrences, '', actor_occurences, sep='\n')
director
Joel Coen      2
Jim McBride    1
Name: count, dtype: int64

actors
John Goodman     3
John Turturro    2
Judy Davis       1
Jeff Bridges     1
Steve Buscemi    1
Dennis Quaid     1
Ellen Barkin     1
Name: count, dtype: int64

Интересные вопросы для изучения