Python:将姓名列表分割为相同大小的子列表

7 投票
2 回答
866 浏览
提问于 2025-04-16 11:28

我有一个名字的列表,比如说 ['Agrajag', 'Colin', 'Deep Thought', ... , 'Zaphod Beeblebrox', 'Zarquon']。现在我想把这个列表分成几个差不多大小的小组,要求这些小组的边界是根据名字的首字母来划分的,比如 A-F、G-L、M-P、Q-Z,而不是 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)

有没有更好的主意呢?

附注:这听起来可能像是作业,但其实是为了一个网页,网页上需要把成员分成5到10个大小差不多的标签。

2 个回答

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"。

你可能会遇到的问题是,如果有两个 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']
4

这里有一个可能有效的方法。不过我觉得应该有更简单的办法,可能会用到 itertools 这个工具。需要注意的是,num_pages 只是大致决定你会得到多少页。

补充说明:哎呀!之前有个bug——最后一组数据被截断了!下面的代码已经修复了这个问题,但要注意最后一页的长度会有点不可预测。另外,我加了 .upper() 来处理可能出现的小写名字的情况。

补充说明2:之前定义字母组的方法效率不高;下面基于字典的代码更具扩展性:

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)

撰写回答