Python:将名称分区列为相同大小的子列表

时间:2011-02-08 20:46:52

标签: python group-by

我有一个名单,例如['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 个答案:

答案 0 :(得分:4)

这可能有用。我确信有一种更简单的方法......可能涉及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 :(得分:1)

由于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”。
  4. 如果其中两个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']