Поиск наиболее распространенного элемента в списке кортежей переменной длины - PullRequest
3 голосов
/ 12 октября 2019

Я пишу код, который возвращает наиболее распространенный номер автобусной остановки на автобусном маршруте (из файла CSV). Первая запись 'bus_routes.csv' в каждой строке - это название маршрута, а остальные записи - это номера автобусных остановок.

def most_common_number(routes):
    routes = load_routes('bus_routes.csv')
    bus_stop_ID = [col[1:] for col in routes]
    return max(sum(set((bus_stop_ID, []), key = sum(bus_stop_ID, []).count)

Когда я запускаю этот код, он возвращает ошибку;TypeError: может только объединить список (не "tuple") в список типа (bus_stop_number) - это список, поэтому я не могу найти, где кортеж существует в моем последнем коде.

1 Ответ

4 голосов
/ 12 октября 2019

Я не могу найти, где в моем последнем коде существует кортеж

Каждый элемент bus_stop_ID является кортежем.

Напомним, у вас есть список переменныхдлины, и вы хотите найти самый распространенный элемент во всей этой структуре.

Звучит как идеальное применение для collections.Counter:

>>> from collections import Counter
>>> bus_stop_ID = [('id1', 'id2', 'id3'), ('id1',), ('id1', 'id3', 'id5')]
>>> [(stop_id, count)] = sum(map(Counter, bus_stop_ID), Counter()).most_common(1)
>>> stop_id
'id1'
>>> count
3

Здесь:

  • map(Counter, bus_stop_ID) подсчитывает идентификаторы автобусных остановок по каждому маршруту отдельно;
  • sum(..., Counter()) объединяет подсчеты по маршрутам;
  • .most_common(1) возвращаетНаиболее распространенный идентификатор автобусной остановки в агрегированных счетах (как одноэлементный список, содержащий 2-кортеж, который состоит из идентификатора автобусной остановки и его счетчика).

Альтернативой является объединение всехмаршрутов (используя sum()), а затем выполните подсчет:

>>> [(stop_id, count)] = Counter(sum(bus_stop_ID, ())).most_common(1)

Это короче, но менее эффективно, поскольку необходимо объединить все маршруты в один (потенциально гигантский) кортеж.

A - несколько причудливый - способ обойти эту неэффективность с помощью itertools.chain():

>>> Counter(itertools.chain(*bus_stop_ID)).most_common(1)
[('id1', 3)]

Это просто перебирает все идентификаторы автобусной остановки на первом маршруте, затем на втором и т. Д., Делая подсчет по пути.

Из любопытства,Я сравнил все три метода с произвольно выбранным списком из 10 000 кортежей, и результаты весьма интересны:

In [11]: %timeit sum(map(Counter, bus_stop_ID), Counter()).most_common(1)
1 loop, best of 3: 235 ms per loop

In [12]: %timeit Counter(sum(bus_stop_ID, ())).most_common(1)
1 loop, best of 3: 2.64 s per loop

In [13]: %timeit Counter(itertools.chain(*bus_stop_ID)).most_common(1)
10 loops, best of 3: 17.3 ms per loop
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...