Opción 1:
key=lambda d:(d['rank']==0, d['rank'])
Opción 2:
key=lambda d:d['rank'] if d['rank']!=0 else float('inf')
Demostración:
"Me me gusta ordenarlo por los valores de rango, ordenando de la siguiente manera: 1-2-3-4-0-0-0. " carteles --original
>>> sorted([0,0,0,1,2,3,4], key=lambda x:(x==0, x))
[1, 2, 3, 4, 0, 0]
>>> sorted([0,0,0,1,2,3,4], key=lambda x:x if x!=0 else float('inf'))
[1, 2, 3, 4, 0, 0]
Comentarios adicionales:?
"Por favor, ¿podría explicar a mí (un principiante de Python) lo que está haciendo lo que puedo ver que es una lambda, que sé que es una función anónima: ¿qué hay entre paréntesis?"- comentario OP
Indexación/notación de corte:
itemgetter('rank')
es lo mismo que lambda x: x['rank']
es lo mismo que la función:
def getRank(myDict):
return myDict['rank']
El [...]
se llama la indexación/notación de división, consulte Explain Python's slice notation - También tenga en cuenta que someArray[n]
es una notación común en muchos lenguajes de programación para la indexación, pero puede no admitir sectores del formulario [start:end]
o [start:end:step]
.
key=
vs cmp=
vs rica comparación:
En cuanto a lo que está pasando, hay dos formas comunes para especificar cómo funciona un algoritmo de ordenación: uno es con una función key
, y el otro es con una cmp
función (ahora obsoleto en Python, pero mucho más versátil). Mientras que una función cmp
le permite especificar arbitrariamente cómo se deben comparar dos elementos (entrada: a
, b
; salida: a<b
o a>b
o a==b
). Aunque es legítimo, no nos da ningún beneficio importante (tendríamos que duplicar el código de una manera incómoda), y una función clave es más natural para su caso. (Ver "objeto rica comparación" de cómo definir implícitamente cmp=
de una manera elegante, pero posiblemente sea excesiva.)
la implementación de su función clave:
Desafortunadamente 0 es un elemento de los números enteros y por lo tanto tiene una orden natural: 0 es normalmente < 1,2,3 ... Por lo tanto, si queremos imponer una regla adicional, tenemos que ordenar la lista en un "nivel superior". Hacemos esto haciendo que la tecla sea una tupla: las tuplas se ordenan primero por su primer elemento, luego por su segundo elemento. True siempre se ordenará después de False, por lo que todos los Trues se ordenarán después de los Falses; luego se ordenarán de forma normal: (True,1)<(True,2)<(True,3)<...
, (False,1)<(False,2)<...
, (False,*)<(True,*)
. La alternativa (opción 2) simplemente asigna a los diccionarios de rango 0 un valor de infinito, ya que se garantiza que está por encima de cualquier rango posible.
Más en general alternativa - objetar rica comparación:
La solución aún más general sería la creación de una clase que representa los registros, a continuación, aplicar __lt__
, __gt__
, __eq__
, __ne__
, __gt__
, __ge__
, y todos los demás rich comparison operators, o alternativamente solo implemente uno de esos y __eq__
y use el @functools.total_ordering
decorator. Esto hará que los objetos de esa clase utilicen la lógica personalizada siempre que utilice operadores de comparación (por ejemplo, x=Record(name='Joe', rank=12)
y=Record(...)
x<y
); dado que la función sorted(...)
usa <
y otros operadores de comparación por defecto en una ordenación de comparación, esto hará que el comportamiento sea automático al ordenar, y en otros casos donde use <
y otros operadores de comparación. Esto puede o no ser excesivo dependiendo de su caso de uso.
Limpiador alternativa - no sobrecargue 0 con la semántica:
debo señalar sin embargo que es un poco artificial para poner detrás de 0s 1,2,3,4, etc. Si esto se justifica depende de si rank = 0 realmente significa rank = 0; si rank = 0 son realmente "inferiores" a rank = 1 (que a su vez son realmente "inferiores" a rank = 2 ...). Si este es realmente el caso, entonces su método está perfectamente bien. Si este no es el caso, puede considerar omitir la entrada 'rank':...
en lugar de establecer 'rank':0
. Posteriormente, se podría solucionar por la respuesta de Lev Levitsky usando 'rank' in d
, o por:
Opción 1 con diferente esquema:
key=lambda d: (not 'rank' in d, d['rank'])
Opción 2 con diferente esquema:
key=lambda d: d.get('rank', float('inf'))
sidenote: Basándose en el la existencia de infinito en python es casi un hack en el límite, por lo que cualquiera de las soluciones mencionadas (tuplas, comparación de objetos), filter-then-concatenate solution de Lev, e incluso tal vez el cmp
solution ligeramente más complicado (escrito por wilson), más generalizable a otros idiomas.
Por favor explique su downvote incorrecto. =) – ninjagecko
Opción 1 funciona! Gracias. – Richard
¿Podría explicarme (un principiante de Python) qué está haciendo? Puedo ver que es una lambda, que sé que es una función anónima: ¿qué hay entre paréntesis? – Richard