2011-02-08 9 views
7

Tengo una lista de nombres, p. ['Agrajag', 'Colin', 'Deep Thought', ... , 'Zaphod Beeblebrox', 'Zarquon']. Ahora quiero dividir esta lista en sublistas de igual tamaño, de modo que los límites de los subgrupos estén en la primera letra de los nombres, por ejemplo, AF, GL, MP, QZ, no A-Fe, Fi-Mo, Mu-Pra , Pre-Z.Python: lista de particiones de nombres en sublistas de igual tamaño

sólo podía llegar a una parition estáticamente tamaño que no tiene el tamaño de los subgrupos en cuenta:

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) 

mejor idea?

P.S .: esto puede parecer un poco como la tarea, pero en realidad es para una página web donde los miembros deben mostrarse en 5-10 pestañas de grupos de igual tamaño.

Respuesta

4

Aquí hay algo que podría funcionar. Sin embargo, estoy seguro de que hay una manera más simple ... que probablemente involucre itertools. Tenga en cuenta que num_pages solo determina aproximadamente cuántas páginas obtendrá realmente.

EDITAR: ¡Vaya! Hubo un error: ¡estaba cortando el último grupo! Lo siguiente debe ser reparado, pero tenga en cuenta que la longitud de la última página será ligeramente impredecible. Además, agregué .upper() para dar cuenta de posibles nombres en minúscula.

EDIT2: El método anterior de definir letter_groups era ineficaz; el siguiente código basado en dict es más escalable:

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) 
+0

Eso parece funcionar razonablemente bien con mis datos reales de alrededor de 500 Nombres. ¡Gracias! –

+0

Ah, bien - no estaba seguro de si se escalaría. – senderle

+0

@piquadrat, gracias por aceptar, pero ¡tenga en cuenta el error! Está arreglado arriba. – senderle

1

Dado que su name_list tiene que ordenarse para que groupby funcione, ¿no puede simplemente verificar cada N de valor y construir sus divisiones de esa manera?

right_endpoints = name_list[N-1::N] 

Y el uso de "A" como su punto final más a la izquierda y "Z" como su punto final más a la derecha, se puede construir las divisiones N consecuencia y todos ellos deben tener el mismo tamaño.

  1. Así, el primer extremo izquierdo sería "A", el primer extremo derecho sería right_endpoints[0].
  2. El siguiente punto final izquierdo sería el carácter después de right_endpoints[0], el siguiente extremo derecho sería right_endpoints[1].
  3. Etc., hasta que llegue al rango N y que tenga un punto final establecido de "Z".

La cuestión es posible que encuentre lo que es si dos de ellos son los mismos right_endpoints ...

edición: ejemplo

>>> 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'] 
+0

Pero él quiere dividir en límites de caracteres iniciales, no solo en cualquier lugar. –

+0

Correcto, la extracción de caracteres inicial se omite para simplificar, pero la idea sigue siendo la misma. Obtenga cada enésima entrada, extraiga lo que desee como definidor de punto final e inicie desde allí. –

Cuestiones relacionadas