2010-04-19 7 views

Respuesta

43

corto y dulce:

sorted(data, key=lambda item: (int(item.partition(' ')[0]) 
           if item[0].isdigit() else float('inf'), item)) 

Esta versión:

  • Obras en Python 2 y Python 3, debido a que:
    • No asume a comparar cadenas y enteros (que no funcionarán en Python 3)
    • No utiliza el parámetro cmp-sorted (que no existe en Python 3)
  • clasificará en la parte del hilo, si las cantidades son iguales
  • salida

Si desea imprimir exactamente como se describe en el ejemplo, entonces:

data = set(['booklet', '4 sheets', '48 sheets', '12 sheets']) 
r = sorted(data, key=lambda item: (int(item.partition(' ')[0]) 
            if item[0].isdigit() else float('inf'), item)) 
print ',\n'.join(r) 
+1

Gran respuesta Daniel – mmrs151

1
>>> a = set(['booklet', '4 sheets', '48 sheets', '12 sheets']) 
>>> def ke(s): 
    i, sp, _ = s.partition(' ') 
    if i.isnumeric(): 
     return int(i) 
    return float('inf') 

>>> sorted(a, key=ke) 
['4 sheets', '12 sheets', '48 sheets', 'booklet'] 
1

conjuntos son inherentemente sin ordenar Tendrá que crear una lista con el mismo contenido y ordenarlo.

+2

No es cierto - la ordenada() incorporada se llevará a cualquier secuencia y devolver una lista ordenada . – PaulMcG

+3

Así que, en lugar de crear una lista y ordenarla, en su lugar utilizas una función integrada para crear una lista ordenada ... Sí, estaba muy lejos. – Rakis

1

Sobre la base de la respuesta de SilentGhost:

In [4]: a = set(['booklet', '4 sheets', '48 sheets', '12 sheets']) 

In [5]: def f(x): 
    ...:  num = x.split(None, 1)[0] 
    ...:  if num.isdigit(): 
    ...:   return int(num) 
    ...:  return x 
    ...: 

In [6]: sorted(a, key=f) 
Out[6]: ['4 sheets', '12 sheets', '48 sheets', 'booklet'] 
83

Jeff Atwood habla de tipo natural y da un ejemplo de una forma de hacerlo en Python. Aquí está mi variación sobre el mismo:

import re 

def sorted_nicely(l): 
    """ Sort the given iterable in the way that humans expect.""" 
    convert = lambda text: int(text) if text.isdigit() else text 
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(l, key = alphanum_key) 

uso como esto:

s = set(['booklet', '4 sheets', '48 sheets', '12 sheets']) 
for x in sorted_nicely(s): 
    print(x) 

Salida:

4 sheets 
12 sheets 
48 sheets 
booklet 

Una ventaja de este método es que no solo trabaja cuando las cuerdas están separados por espacios. También funcionará para otros separadores, como el período en los números de versión (por ejemplo, 1.9.1 viene antes de 1.10.0).

+0

Hola Jeff, Muchas gracias. Eso es exactamente lo que estaba buscando. Buena suerte. – mmrs151

+2

¿Es posible modificar esto para obtener una lista de tuplas basadas en el primer valor de la tupla?Ejemplo: '[('b', 0), ('0', 1), ('a', 2)]' está ordenado a '[('0', 1), ('a', 2), ('b', 0)] ' – paragbaxi

+3

Esta función distingue entre mayúsculas y minúsculas. Las cuerdas en mayúsculas tendrán prioridad. Para arreglar esto agregue '.lower()' a 'key' en' re.split'. – zamber

6

Una manera simple es dividir las cadenas en partes numéricas y no numéricas y usar el orden de tupla de python para ordenar las cadenas.

import re 
tokenize = re.compile(r'(\d+)|(\D+)').findall 
def natural_sortkey(string):   
    return tuple(int(num) if num else alpha for num, alpha in tokenize(string)) 

sorted(my_set, key=natural_sortkey) 
3

se sugirió que puedo renovar this answer aquí ya que funciona muy bien para este caso también

from itertools import groupby 
def keyfunc(s): 
    return [int(''.join(g)) if k else ''.join(g) for k, g in groupby(s, str.isdigit)] 

sorted(my_list, key=keyfunc) 

Demostración:

>>> my_set = {'booklet', '4 sheets', '48 sheets', '12 sheets'} 
>>> sorted(my_set, key=keyfunc) 
['4 sheets', '12 sheets', '48 sheets', 'booklet'] 

Para python3 que es necesario modificar ligeramente (esta versión funciona bien en python2 demasiado)

def keyfunc(s): 
    return [int(''.join(g)) if k else ''.join(g) for k, g in groupby('\0'+s, str.isdigit)] 
1

Para personas atrapadas con una versión pre-2.4 de Python, sin la maravillosa función sorted(), una forma rápida de ordenar conjuntos es:

l = list(yourSet) 
l.sort() 

Esto no responde a la pregunta específica anterior (12 sheets aparecerá antes de 4 sheets), pero podría ser útil para las personas que provienen de Google.

4

Debe consultar la biblioteca de terceros natsort. Su algoritmo es general, por lo que funcionará para la mayoría de las entradas.

>>> import natsort 
>>> your_list = set(['booklet', '4 sheets', '48 sheets', '12 sheets']) 
>>> print ',\n'.join(natsort.natsorted(your_list)) 
4 sheets, 
12 sheets, 
48 sheets, 
booklet 
0

Respuesta genérica para ordenar cualquier número en cualquier posición en una matriz de cadenas. Funciona con Python 2 & 3.

def alphaNumOrder(string): 
    """ Returns all numbers on 5 digits to let sort the string with numeric order. 
    Ex: alphaNumOrder("a6b12.125") ==> "a00006b00012.00125" 
    """ 
    return ''.join([format(int(x), '05d') if x.isdigit() 
        else x for x in re.split(r'(\d+)', string)]) 

muestra:

s = ['a10b20','a10b1','a3','b1b1','a06b03','a6b2','a6b2c10','a6b2c5'] 
s.sort(key=alphaNumOrder) 
s ===> ['a3', 'a6b2', 'a6b2c5', 'a6b2c10', 'a06b03', 'a10b1', 'a10b20', 'b1b1'] 

Parte de la respuesta is from there

Cuestiones relacionadas