#python #list #sorting #tuples
#python #Список #сортировка #кортежи
Вопрос:
Мне нужно создать функцию, которая на основе заданных данных определяет количество станций мониторинга у конкретной реки. Затем эта функция должна вернуть первые N объектов в списке кортежей (название реки, количество станций), которые отсортированы в порядке убывания количества станций.
Однако некоторые реки могут иметь одинаковое количество станций, и их нужно рассматривать как одну запись в возвращаемом списке, но я не уверен, как я могу это сделать. (Возвращаемый список может содержать более N объектов, но только N номеров… если это имеет смысл)
Функция, которую я создал до сих пор, выглядит следующим образом:
def rivers_by_station_number(stations, N):
riv_names = set()
for station in stations:
riv_names.add(station.river)
num_stations = []
for name in riv_names:
n = 0
for station in stations:
if station.river == name:
n = 1
else:
pass
num_stations.append(n)
lst_tuple = list(zip(riv_names, num_stations))
lst_tuple_sort = sorted(lst_tuple, key=lambda x: x[1], reverse=True)
return lst_tuple_sort[:N]
Есть ли функция сортировки, с помощью которой я могу вернуть первые N объектов отсортированного списка, рассматривая те же числа, что и единственная запись?
Дополнительная информация
Когда я запускаю функцию, где N = 9, я получаю следующие результаты:
[('River Thames', 55), ('River Avon', 32), ('River Great Ouse', 30), ('River Derwent', 25), ('River Aire', 24), ('River Calder', 22), ('River Severn', 21), ('River Stour', 19), ('River Ouse', 18)]
К счастью для меня, ни одна из рек в первых 9 объектах в отсортированном списке не имеет одинакового количества станций мониторинга, однако я все равно хотел бы реализовать вышеуказанное в моей функции, поскольку данные всегда меняются.
Большое вам спасибо!!!
Комментарии:
1. То есть вы имеете в виду возврат 10 станций, если между двумя из первых девяти есть связь?
2. @tripleee да! извините, если я не слишком четко изложил это в своих описаниях, хахаха, не очень хорошо в этом разбираюсь
Ответ №1:
Нет встроенной функции, которая выполняла бы то, что вы просите (о чем я знаю), поэтому, по-видимому, наилучшим подходом является то, что вы делаете, группируя реки по количеству станций, сортируя по количеству станций, затем беря первую N
из этого отсортированного списка.
Я бы также разбил ваш код на две отдельные функции: одну, которая принимает список станций и собирает их по названию реки, и вторую, которая берет эти пары (название реки, количество станций) и извлекает первую N
из них.
Функция для сбора станций по реке
Единственный способ действительно сделать это — перебрать все станции и собрать их.
from collections import Counter
def collect_stations( stations ):
"""
:param stations: List of station objects.
:returns: Dictionary like object of name-station count pairs.
"""
river_count = {}
names = [ s.river for s in stations ]
return Counter( names )
Функция, которая возвращает первые N
станции
Вот версия, которая немного более компактна
def highest_counts( river_stations, N, flatten = True ):
"""
:param river_stations: Dictionary like object of name-count pairs.
:param N: Number of count groups to return.
:param flatten: Flatten list of rivers.
:returns: If flatten is True returns a list of ( name, count ) tuples of N unique counts. i.e. Rivers with the same number of counts are treated as one element. If flatten is False, a dictionary of { count: [ ( name, count ) ] is returned, with N count keys.
"""
# group rivers by number of stations
grouped = {}
for name, count in river_stations.items():
if count not in grouped:
# add number group if it doesn't exist
grouped[ count ] = []
grouped[ count ].append( ( name, count ) )
# sort groups by number of stations
grouped = [ ( c, l ) for c, l in grouped.items() ]
grouped.sort( key = lambda x: x[ 0 ], reverse = True )
# get first N number groups
stats = grouped[ :N ]
if flatten:
stats = [
river
for num_list in stats
for river in num_list[ 1 ]
]
return stats
Другим подходом было бы отсортировать начальный список, затем брать элементы до N
тех пор, пока не будут видны номера станций.
from collections import Counter
def highest_counts( river_stations, N ):
"""
:param river_stations: Dictionary like object of name-count pairs.
:param N: Number of count groups to return.
:returns: List of ( name, count ) tuples of N unique counts. i.e. Rivers with the same number of counts are treated as one element.
"""
# sorts by number of stations
river_stations_list = [ ( name, count ) for name, count in river_stations.items() ]
s = sorted( river_stations_list, key = lambda x: x[ 1 ], reverse = True )
# gets number of stations for each element
nums = [ x[ 1 ] for x in s ]
# calculates how many indices incorporate first N number groups
freqs = list( Counter( nums ).values() )
ind = sum( freqs[ :N ] )
# return first elements that incorporate N number groups
return s[ :ind ]
При быстрой проверке производительности вторая версия становится намного быстрее для больших входных данных.
Заключительная функция
Затем ваша конечная функция объединит два вышеперечисленных.
def rivers_by_station_number( stations, N ):
"""
:param stations: List of station objects.
:param N: Number of count groups to return.
:returns: List of ( name, count ) tuples of N unique counts. i.e. Rivers with the same number of counts are treated as one element.
"""
collected = collect_stations( stations ):
return highest_counts( collected, N )
Ответ №2:
Ваш код неэффективен, сначала я его оптимизирую:
def rivers_by_station_number(stations, N):
river_station = {}
for station in stations:
river_station[station.river] = river_station.get(station.river, 0) 1
sorted_river_station = sorted(river_station.items(), key=lambda x: x[1], reverse = True)
length = len(sorted_river_station)
if N>= length: return sorted_river_station
min_station_count = sorted_river_station[N-1][1]
while N<length and sorted_river_station[n] == min_station_count:
N =1
return sorted_river_station[:N]
Что я делаю, так это нахожу количество станций N-й реки и выполняю итерацию от этой реки до конца, проверяя, имеют ли остальные реки одинаковое количество станций.
Комментарии:
1. Автор вопроса утверждает, что
... considering the same numbers as a singular entry?
, однако, похоже, что ваш код учитывает связи только в последней позиции, но не в промежуточных позициях. Похоже, что автор хочет, чтобы связи во всех позициях не учитывались при окончательном подсчете возвращаемых элементов.2. @bicarlsen, из текста не так понятно, я обновлю свой код