2015-07-13 13 views
-2

У меня есть вопрос относительно текущей программы, которую я пытаюсь изменить. Текущая программа у меня есть:Более сложная сортировка: как сортировать по категории?

def extract_names(filename): 
    names = [] 
    f = open(filename, 'rU') 
    text = f.read() 

    yearmatch = re.search(r'Popularity\sin\s(\d\d\d\d)', text) 
    if not yearmatch: 
    sys.stderr.write('unavailable year\n') 
    sys.exit(1) 
    year = yearmatch.group(1) 
    names.append(year) 

    yeartuples = re.findall(r'<td>(\d+)</td><td>(\w+)</td>\<td>(\w+)</td>', text)#finds all patterns of date, boyname, and girlname, creates tuple) 

    rankednames = {} 
    for rank_tuple in yeartuples: 
    (rank, boyname, girlname) = rank_tuple 
    if boyname not in rankednames: 
     rankednames[boyname] = rank 
    if girlname not in rankednames: 
     rankednames[girlname] = rank 
    sorted_names = sorted(rankednames.keys(), key=lambda x: int(rankednames[x]), reverse = True) 
    for name in sorted_names: 
    names.append(name + " " + rankednames[name]) 
    return names[:20] 
#Boilerplate from this point** 

def main(): 

    args = sys.argv[1:] 

    if not args: 
    print 'usage: [--summaryfile] file [file ...]' 
    sys.exit(1) 

    summary = False 
    if args[0] == '--summaryfile': 
    summary = True 
    del args[0] 

    for filename in args: 
    names = extract_names(filename) 
    text = '\n'.join(names) 

    if summary: 
     outf = open(filename + '.summary', 'w') 
     outf.write(text + '\n') 
     outf.close() 
    else: 
     print text 

if __name__ == '__main__': 
    main() 

принимает информацию с веб-сайта о самых популярных детских имен в определенный год в таблице, эти данные используются для создания списка и распечатать список имен детей в порядке от наименьшего ранга (1000) до наивысшего ранга (1). Модификация, которую я пытаюсь сделать, должна сортировать все имена по алфавиту (первая), но внутри каждой группы букв (группа всех а, группа всех букв и т. Д.). Я пытаюсь сортировать имена по убыванию в пределах буквенных групп, поэтому наименьшее ранжированное имя, которое начинается с a, будет первым именем, которое будет отображаться. Первоначально я мог это сделать, изменив функцию лямбда так, чтобы sorted_names = sorted(rankednames.keys(),key=lambda x: (x[0], int(rankednames[x], reverse = True)), однако, я хочу иметь возможность достичь этого без модификация лямбда-функции.

+1

Почему вы не можете изменить функцию лямбда? –

+0

Возможный дубликат [Более сложная сортировка: как скопировать данные и отсортировать данные по категориям? (Python)] (http://stackoverflow.com/questions/31373701/more-complex-sorting-how-to-cateorize-data-and-sort-the-data-within-categories) – Manhattan

ответ

0

Очевидное исправление действительно заключается в том, чтобы изменить вашу лямбда-функцию, чтобы она вернула 2-кортеж (letter, rank). Так как вы хотите, чтобы отсортировать увеличиваясь на письме и уменьшение по рангу, вы хотите, чтобы свести на нет последних (а не с помощью reverse=True):

sorted_names = sorted(rankednames, key=lambda x: (x[0], -int(rankednames[x]))) 

Единственной альтернативы я могу думать о том, чтобы в два раза сортировать, первый по рангу (в обратном порядке), а затем по первой букве:

sorted_names = sorted(sorted(rankednames, 
          key=lambda x: int(rankednames[x]), 
          reverse=True), 
         key=lambda x: x[0]) 

Это работает, потому что Timsort Python является стабильным (он держит равен по ключу значения в том же порядке, что они имели на входе). Вероятно, это будет немного медленнее, чем сортировка только один раз, хотя в среднем случае все равно O(N log(N)).

Смежные вопросы