¿Cómo funciona la función min / max en una lista anidada?

Digamos que hay una lista anidada, como:

my_list = [[1, 2, 21], [1, 3], [1, 2]] 

Cuando se llama a la función min() en esto:

 min(my_list) 

La salida recibida es

 [1, 2] 

¿Por qué y cómo funciona? ¿Cuáles son algunos casos de uso de la misma?

¿Cómo se comparan las listas y otras secuencias en Python?

Las listas (y otras secuencias) en Python se comparan lexicográficamente y no se basan en ningún otro parámetro.

Los objetos de secuencia pueden compararse con otros objetos con el mismo tipo de secuencia. La comparación utiliza ordenamiento lexicográfico : primero se comparan los dos primeros elementos, y si difieren esto determina el resultado de la comparación; si son iguales, se comparan los dos elementos siguientes, y así sucesivamente, hasta que se agote cualquiera de las secuencias.


¿Qué es la clasificación lexicográfica?

De la página de Wikipedia sobre clasificación lexicográfica.

El orden lexicográfico o lexicográfico (también conocido como orden léxico, orden del diccionario, orden alfabético o producto lexicográfico) es una generalización de la forma en que el orden alfabético de las palabras se basa en el orden alfabético de sus letras componentes.

La función min devuelve el valor más pequeño en el iterable . Entonces, el valor lexicográfico de [1,2] es el menor en esa lista. Puedes comprobarlo utilizando [1,2,21]

 >>> my_list=[[1,2,21],[1,3],[1,2]] >>> min(my_list) [1, 2] 

¿Qué está pasando en este caso de min ?

En cuanto al elemento en my_list , primero [1,2,21] y [1,3] . Ahora de los docs

Si dos elementos que deben compararse son secuencias del mismo tipo , la comparación lexicográfica se realiza de forma recursiva .

Por lo tanto, el valor de [1,1,21] es menor que [1,3] , porque el segundo elemento de [1,3] , que es, 3 es lexicográficamente más alto que el valor del segundo elemento de [1,1,21] , que es, 1 .

Ahora comparando [1,2] y [1,2,21] , y agregando otra referencia de los documentos

Si una secuencia es una subsecuencia inicial de la otra, la secuencia más corta es la más pequeña (menor).

[1,2] es una [1,2,21] inicial de [1,2,21] . Por lo tanto, el valor de [1,2] en general es menor que el de [1,2,21] . Por lo tanto, [1,2] se devuelve como la salida.

Esto puede ser validado usando la función sorted

 >>> sorted(my_list) [[1, 2], [1, 2, 21], [1, 3]] 

¿Qué pasa si la lista tiene múltiples elementos mínimos?

Si la lista contiene elementos mínimos duplicados, se devuelve el primero

 >>> my_list=[[1,2],[1,2]] >>> min(my_list) [1, 2] 

Esto se puede confirmar mediante la llamada a la función id .

 >>> my_list=[[1,2],[1,2]] >>> [id(i) for i in my_list] [140297364849368, 140297364850160] >>> id(min(my_list)) 140297364849368 

¿Qué debo hacer para evitar la comparación lexicográfica en min ?

Si la comparación requerida no es lexicográfica, entonces se puede usar el argumento key (como lo menciona Padraic )

La función min tiene un argumento opcional adicional llamado key . El argumento key toma una función.

El argumento de clave opcional especifica una función de ordenamiento de un argumento como la que se usa para list.sort() . El argumento clave, si se proporciona, debe estar en forma de palabra clave (por ejemplo, min(a,b,c,key=func) ).

Por ejemplo, si necesitamos el elemento más pequeño por longitud, necesitamos usar la función len .

 >>> my_list=[[1,2,21],[1,3],[1,2]] >>> min(my_list,key=len) # Notice the key argument [1, 3] 

Como podemos ver aquí se devuelve el primer elemento más corto.


¿Qué pasa si la lista es heterogénea?

Hasta Python2

Si la lista es heterogénea, los nombres de los tipos se consideran para ordenación, verifique las Comparaciones ,

Los objetos de diferentes tipos, excepto los números, están ordenados por sus nombres de tipo

Por lo tanto, si coloca un int y una list allí, obtendrá el valor entero como el más pequeño, ya que i es de menor valor que l . De manera similar, '1' sería de mayor valor que ambos.

 >>> my_list=[[1,1,21],1,'1'] >>> min(my_list) 1 

Python3 y en adelante

Sin embargo, esta técnica confusa fue eliminada en Python3 . Ahora plantea un TypeError . Lee lo nuevo en Python 3.0

Los operadores de comparación de ordenación ( < , <= , >= , > ) TypeError una excepción TypeError cuando los operandos no tienen un ordenamiento natural significativo. Por lo tanto, expresiones como 1 < '' , 0 > None o len <= len ya no son válidas y, por ejemplo, None < None genera TypeError lugar de devolver False . Un corolario es que la clasificación de una lista heterogénea ya no tiene sentido: todos los elementos deben ser comparables entre sí .

 >>> my_list=[[1,1,21],1,'1'] >>> min(my_list) Traceback (most recent call last): File "", line 1, in  TypeError: unorderable types: int() < list() 

Pero funciona para tipos comparables , por ejemplo

 >>> my_list=[1,2.0] >>> min(my_list) 1 

Aquí podemos ver que la list contiene valores float y valores int . Pero como float y int son tipos comparables, la función min funciona en este caso.

Un caso de uso simple para la clasificación lexicográfica es hacer una clase de namedtuple clasificable.

 from collections import namedtuple Time = namedtuple('Time', ['hours', 'minutes', 'seconds']) t1 = Time(hours=8, minutes=15, seconds=30) t2 = Time(hours=8, minutes=15, seconds=0) t3 = Time(hours=8, minutes=30, seconds=30) t4 = Time(hours=7, minutes=15, seconds=30) assert min(t1, t2, t3, t4) == t4 assert max(t1, t2, t3, t4) == t3 

Se comparan dos listas de elementos sabios

Incluso si los tamaños de dos listas son diferentes, las dos listas se comparan de manera inteligente a partir del primer elemento.

Ahora suponga que todos los elementos de una lista han sido verificados y son los mismos y no hay ningún elemento siguiente en la lista más corta. Entonces la lista más corta se declara más pequeña que la más larga.

Ejemplos:

 >>> [1,2]<[1,3] True >>> [1,2]<[1,2,21] True >>> [1,3]<[1,2,21] False >>>[1,2,22]<[1,2,21] False >>>[1]<[1,2,21] True >>> 

compara las listas elementwise:

 >>> [1,2]<[1,3] True >>> [1,2]<[1,2,21] True >>>