Python: разделить список имен на одинаковые по размеру подсписки - PullRequest
7 голосов
/ 08 февраля 2011

У меня есть список имен, например, ['Agrajag', 'Colin', 'Deep Thought', ... , 'Zaphod Beeblebrox', 'Zarquon']. Теперь я хочу разделить этот список на примерно одинаковые по размеру подсписки, чтобы границы подгрупп были по первой букве имени, например, AF, GL, MP, QZ, а не A-Fe, Fi-Mo, Mu-Pra Pre-Z.

Я мог бы только создать разделение статического размера, которое не учитывает размер подгрупп:

import string, itertools

def _group_by_alphabet_key(elem):
    char = elem[0].upper()
    i = string.ascii_uppercase.index(char)
    if i > 19:
        to_c = string.ascii_uppercase[-1];
        from_c = string.ascii_uppercase[20]
    else:
        from_c = string.ascii_uppercase[i/5*5]
        to_c = string.ascii_uppercase[i/5*5 + 4]
    return "%s - %s" % (from_c, to_c)

subgroups = itertools.groupby(name_list, _group_by_alphabet_key)

Есть идеи получше?

P.S .: это может звучать как домашнее задание, но на самом деле это для веб-страницы, где участники должны отображаться в 5-10 вкладках групп одинакового размера.

Ответы [ 2 ]

4 голосов
/ 09 февраля 2011

Вот кое-что, что может сработать.Я уверен, что есть более простой способ ... вероятно, с участием itertools.Обратите внимание, что num_pages только приблизительно определяет, сколько страниц вы фактически получите.

РЕДАКТИРОВАТЬ: К сожалению!Была ошибка - это отрезало последнюю группу!Ниже должно быть исправлено, но обратите внимание, что длина последней страницы будет немного непредсказуемой.Кроме того, я добавил .upper() для учета возможных строчных имен.

EDIT2: предыдущий метод определения letter_groups был неэффективным;приведенный ниже код на основе dict более масштабируем:

names = ['Agrajag', 'Colin', 'Deep Thought', 'Ford Prefect' , 'Zaphod Beeblebrox', 'Zarquon']
num_pages = 3

def group_names(names, num_pages):
    letter_groups = defaultdict(list)
    for name in names: letter_groups[name[0].upper()].append(name)
    letter_groups = [letter_groups[key] for key in sorted(letter_groups.keys())]
    current_group = []
    page_groups = []
    group_size = len(names) / num_pages
    for group in letter_groups:
        current_group.extend(group)
        if len(current_group) > group_size:
            page_groups.append(current_group)
            current_group = []
    if current_group: page_groups.append(current_group)

    return page_groups

print group_names(names, num_pages)
1 голос
/ 09 февраля 2011

Поскольку ваш name_list должен быть отсортирован для работы groupby, разве вы не можете просто проверить каждое N-е значение и построить свои деления таким образом?

right_endpoints = name_list[N-1::N]

И используя "A" каксамая левая конечная точка и "Z" как самая правая конечная точка, вы можете соответственно построить N делений, и все они должны иметь одинаковый размер.

  1. Итак, первая левая конечная точка будет "A",первая правая конечная точка будет right_endpoints[0].
  2. Следующая левая конечная точка будет символом после right_endpoints[0], следующая правая конечная точка будет right_endpoints[1].
  3. и т. д., пока вы не нажметеN-й диапазон, в котором установлена ​​конечная точка "Z".

Проблема, с которой вы можете столкнуться, заключается в том, что если два из этих right_endpoints совпадают ...

редактировать: пример

>>> names = ['Aaron', 'Abel', 'Cain', 'Daniel', 'Darius', 'David', 'Ellen', 'Gary', 'James', 'Jared', 'John', 'Joseph', 'Lawrence', 'Michael', 'Nicholas', 'Terry', 'Victor', 'Zulu']
>>> right_ends, left_ends = names[2::3], names[3::3]
>>> left_ends = ['A'] + left_ends
>>> left_ends, right_ends
>>> ["%s - %s" % (left, right) for left, right in zip(left_ends, right_ends)]
['A - Cain', 'Daniel - David', 'Ellen - James', 'Jared - Joseph', 'Lawrence - Nicholas', 'Terry - Zulu']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...