Un list es una colección mutable de elementos en secuencia.
Como la mayoría de las colecciones (consulta las incorporadas tuple, dict y set), los arrays pueden contener referencias a cualquier tipo o tipos de datos, incluidas otras arrays.
Se consideran una secuencia en Python y pueden copiarse total o parcialmente mediante la notación de rebanadas.
Como cualquier secuencia, los elementos dentro de lists pueden referenciarse mediante un número de 0-based index desde la izquierda, o de -1-based index desde la derecha.
Los arrays admiten tanto las operaciones comunes de secuencia como las operaciones de secuencia mutables, tales como min(<list>)/max(<list>), <list>.index(), <list>.append() y <list>.reverse().
Se puede iterar sobre los elementos con la construcción for item in <list>, y con for index, item in enumerate(<list>) cuando se necesitan tanto el elemento como su índice.
Python proporciona muchos métodos útiles para trabajar con arrays.
Como los arrays son mutables, los métodos de array alteran el objeto array original que se pasa al método.
Si no queremos mutarlo, hay que hacer una shallow copy (como mínimo) del list original mediante slice o <list>.copy().
Añadir elementos al final de un array existente puede hacerse con <list>.append(<item>):
>>> numbers = [1, 2, 3]
>>> numbers.append(9)
>>> numbers
[1, 2, 3, 9]
En lugar de añadir al final, <list>.insert(<index>, <item>) añade el elemento a un índice concreto dentro del array.
<index> es el índice del elemento delante del cual quieres que aparezca el nuevo elemento.
<item> es el elemento que se va a insertar.
Nota: Si <index> es 0, el elemento se añadirá al principio del array.
Si <index> es mayor que el último índice del array, el elemento se añadirá en la última posición, lo que equivale a usar <list>.append(<item>).
>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)
>>> numbers
[-2, 1, 2, 3]
>>> numbers.insert(1, 0)
>>> numbers
[-2, 0, 1, 2, 3]
Se puede combinar un iterable con un array existente (concatenando los dos) mediante <list>.extend(<iterable>).
<list>.extend(<iterable>) desempaqueta el iterable proporcionado y añade sus elementos en el mismo orden al final del array de destino.
Usar <list>.append(<item>) en esta situación añadiría todo el iterable como un único elemento.
>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]
>>> numbers.extend(other_numbers)
>>> numbers
[1, 2, 3, 5, 6, 7]
>>> numbers.extend([8, 9])
>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]
<list>.remove(<item>) puede usarse para eliminar un elemento del array.
<list>.remove(<item>) lanzará un ValueError si el elemento no está presente en el array.
>>> numbers = [1, 2, 3]
>>> numbers.remove(2)
>>> numbers
[1, 3]
# Trying to remove a value that is not in the list throws a ValueError.
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list
Como alternativa, usar el método <list>.pop(<index>) elimina y devuelve con return un elemento para poder usarlo.
<list>.pop(<index>) acepta un parámetro opcional: el index del elemento que se va a eliminar y devolver.
Si no se especifica el argumento opcional <index>, se eliminará y devolverá el último elemento del array.
Si <index> es un número mayor que el último índice del array, se lanzará un IndexError.
>>> numbers = [1, 2, 3]
>>> numbers.pop(0)
1
>>> numbers
[2, 3]
>>> numbers.pop()
3
>>> numbers
[2]
# This will throw an error because there is only index 0.
>>> numbers.pop(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
Todos los elementos pueden eliminarse de un list con <list>.clear(). No acepta ningún parámetro.
>>> numbers = [1, 2, 3]
>>> numbers.clear()
>>> numbers
[]
El orden de los elementos del array puede invertirse in situ con <list>.reverse(). Esto mutará el array original.
>>> numbers = [1, 2, 3]
>>> numbers.reverse()
>>> numbers
[3, 2, 1]
Un array puede reordenarse in situ con la ayuda de <list>.sort().
El orden predeterminado es ascendente desde la izquierda.
La documentación de Python ofrece consejos y técnicas adicionales para ordenar.
De 2002 a 2022, Python usaba internamente un algoritmo llamado Timsort para ordenar los arrays, pero cambió a Powersort a partir de Python 3.11.
Puedes leer más detalles y el debate sobre el cambio por parte del equipo central de Python en la issue 78742 de GitHub.
Para detalles técnicos sobre el algoritmo, consulta el artículo de J. Ian Munro y Sebastian Wild Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
# The default sort order is *ascending*.
>>> names.sort()
>>> names
["Bruce", "Natasha", "Thor", "Tony"]
Para ordenar un array en orden descendente, pasa un argumento reverse=True al método:
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)
>>> names
["Tony", "Thor", "Natasha", "Bruce"]
Cuando no se desee mutar el list original, pueden usarse las funciones incorporadas sorted() y reversed().
sorted(<list>) devuelve una copia ordenada y acepta los mismos parámetros que <list>.sort().
reversed(<list>) devuelve un iterador que produce los elementos del array en orden inverso.
Iterators se tratará en detalle en otro ejercicio.
Para encontrar el número de apariciones de un elemento en un array puede usarse <list>.count(<item>).
Devuelve el número total de veces que <item> aparece como elemento del array.
>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]
>>> items.count(1)
3
<list>.index(<item>) devuelve el número de índice de la primera aparición de un elemento dado.
Si no hay ninguna aparición, se lanza un ValueError.
La indexación es 0-based desde la izquierda, lo que significa que la posición del primer elemento es el índice 0.
También se admite la indexación desde la derecha, empezando por el índice -1.
>>> items = [7, 4, 1, 0, 2, 5]
>>> items.index(4)
1
>>> items.index(10)
ValueError: 10 is not in list
Proporcionar los índices start y end busca dentro de una sección concreta del array:
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> names.index("Tina")
0
>>> names.index("Tina", 2, 5)
3
Si no se necesita la posición exacta de un elemento, el operador incorporado in es más eficiente para verificar la pertenencia.
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> "Thomas" in names
True
Recuerda que las variables en Python son nombres que apuntan a objetos subyacentes.
Los nombres pueden vincularse o revincularse a distintos objetos a lo largo de la vida de un programa.
Asignar un objeto list a un nuevo nombre de variable no copia el objeto ni ninguno de sus datos referenciados.
El nombre nuevo y el antiguo apuntarán ambos al mismo objeto list.
Además, los arrays son objetos de tipo contenedor: para ahorrar espacio, los contenedores solo guardan referencias a los elementos que contienen, no los elementos en sí.
Esta «optimización» puede tener consecuencias inesperadas para quien no está atento.
<list>.copy() crea un nuevo objeto list, pero no crea nuevos objetos para los elementos referenciados del array: la copia es «superficial».
Una shallow copy suele bastar cuando quieres añadir o eliminar elementos de uno de los objetos list sin modificar el otro.
Pero si existe alguna posibilidad de que los elementos subyacentes de un list se muten por accidente (mutando con ello todas las copias superficiales relacionadas), debe usarse copy.deepcopy() del módulo copy para crear una copia completa, o «profunda», de todas las referencias y los objetos.
Para una explicación detallada del comportamiento de los nombres, los valores, los arrays y los arrays anidados, echa un vistazo a esta excelente entrada de blog de Ned Batchelder: Names and values: making a game board. Shallow vs Deep Copying of Python Objects también ofrece un buen resumen de las consideraciones sobre las copias.