Запрос о печати первых 9 объектов списка

#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, из текста не так понятно, я обновлю свой код