Cómo dividir una lista en partes pares en Python

En este artículo, mostramos cómo dividir una lista en partes del mismo tamaño en Python, dividiéndolas en partes de N elementos y en N partes del mismo tamaño.

Introducción

Dividir cadenas y listas son actividades de programación comunes en Python y otros lenguajes. A veces tenemos que dividir nuestros datos de formas peculiares, pero más comúnmente, en partes iguales.

El lenguaje no tiene una función integrada para hacer esto y en este tutorial, veremos cómo dividir una lista en partes iguales en Python.

Para la mayoría de los casos, puede obtener mediante el uso de generadores:

1
2
3
def chunk_using_generators(lst, n):
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

Sin embargo, hay otras formas interesantes de hacer esto, ¡cada una con sus propias ventajas y desventajas!

Dividir una lista en partes pares de N elementos

Una lista se puede dividir en función del tamaño del fragmento definido. Esto significa que podemos definir el tamaño del trozo. Si el subconjunto de la lista no se ajusta al tamaño del fragmento definido, se deben insertar rellenos en el lugar de los contenedores de elementos vacíos. Usaremos Ninguno en esos casos.

Vamos a crear un nuevo archivo llamado chunk_based_on_size.py y agregar los siguientes contenidos:

1
2
3
4
5
6
7
8
9
def chunk_based_on_size(lst, n):
    for x in range(0, len(lst), n):
        each_chunk = lst[x: n+x]

        if len(each_chunk) < n:
            each_chunk = each_chunk + [None for y in range(n-len(each_chunk))]
        yield each_chunk

print(list(chunk_based_on_size([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 7)))

La función chunk_based_on_size() anterior toma los argumentos: lst para la lista y chunk_size para un número por el que dividirla. La función itera a través de la lista con un incremento del tamaño de fragmento n. Se espera que cada fragmento tenga el tamaño dado como argumento. Si no hay suficientes elementos para hacer una división del mismo tamaño, los elementos restantes no utilizados se rellenan con Ninguno.

La ejecución de este script devuelve la siguiente lista de listas:

1
2
$ python3 chunk_based_on_size.py
[[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, None]]

La lista se ha dividido en partes iguales de 7 elementos cada una.

Python tiene utilidades para simplificar este proceso. Podemos usar la función zip_longest de itertools para simplificar la función anterior. Vamos a crear un nuevo archivo chunk_using_itertools.py y agregar el siguiente código:

1
2
3
4
5
6
7
from itertools import zip_longest

def chunk_using_itertools(lst):
    iter_ = iter(lst)
    return list(zip_longest(iter_, iter_, iter_, iter_, iter_, iter_, iter_))

print(chunk_using_itertools([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]))

Este código itera los elementos y devuelve un fragmento de la longitud deseada, según los argumentos que proporcione. Hemos puesto 7 argumentos iter_ aquí. La función zip_longest() agrega y devuelve elementos de cada iterable. En este caso, agregaría los elementos de la lista que se itera 7 veces de una sola vez. Esto luego crea numerosos iteradores que contienen 7 elementos secuenciales, que luego se convierten en una lista y se devuelven.

Cuando ejecute este fragmento, dará como resultado:

1
2
$ python3 chunk_using_itertools.py
[[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, None]]

Esta función más corta produce la misma entrada. Sin embargo, es mucho más limitado ya que tenemos que escribir manualmente cuántos elementos queremos en el código, y es un poco incómodo simplemente poner un montón de iter_s en la llamada zip_longest().

La mejor solución sería usar generadores. Vamos a crear un nuevo archivo, chunk_using_generators.py:

1
2
3
4
5
def chunk_using_generators(lst, n):
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

print(list(chunk_using_generators([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 7)))

Este generador genera una sublista que contiene n elementos. Al final, habría producido una sublista para cada fragmento. Ejecutar este código produce esta salida:

1
2
$ python3 chunk_using_generators.py
[[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13]]

Esta solución funciona mejor si no necesita relleno con Ninguno o de otra manera.

Dividir una lista en N partes pares

En la sección anterior, dividimos la lista según el tamaño de los fragmentos individuales para que cada fragmento tenga la misma cantidad de elementos. Hay otra forma de interpretar este problema. ¿Qué hacemos cuando queremos dividir una lista no en función de la cantidad de elementos en cada fragmento, sino en la cantidad de fragmentos que queremos crear?

Por ejemplo, en lugar de dividir una lista en fragmentos donde cada fragmento tiene 7 elementos, queremos dividir una lista en 7 fragmentos pares. En este caso, es posible que no sepamos el tamaño de cada trozo.

La lógica es similar a las soluciones anteriores, sin embargo, el tamaño del fragmento es el valor máximo de la longitud de la lista dividido por la cantidad de fragmentos requeridos. De manera similar a los ejemplos de código anteriores, si un fragmento tiene lugares vacantes, estos se llenarán con el valor de relleno Ninguno:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import math

def chunk_based_on_number(lst, chunk_numbers):
    n = math.ceil(len(lst)/chunk_numbers)

    for x in range(0, len(lst), n):
        each_chunk = lst[x: n+x]

        if len(each_chunk) < n:
            each_chunk = each_chunk + [None for y in range(n-len(each_chunk))]
        yield each_chunk

print(list(chunk_based_on_number([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], chunk_numbers=7)))

Determinamos cuántas listas necesitamos para crear y almacenar ese valor en n. Luego creamos una sublista para los dos elementos a la vez, rellenando la salida en caso de que el tamaño de nuestro fragmento sea más pequeño que la longitud deseada.

Cuando ejecutemos ese archivo veremos:

1
2
$ python3 chunk_based_on_number.py
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, None]]

Como se ve en el resultado anterior, la lista se ha dividido en 7 listas individuales de igual tamaño, en función del argumento chunk_numbers proporcionado.

Conclusión

En este artículo, hemos visto algunas de las formas en que una lista se puede dividir en partes y listas de tamaño uniforme en función de métodos personalizados y mediante el uso de módulos integrados.

Las soluciones mencionadas en este tutorial no se limitan a las definidas aquí, sino que también existen muchas otras formas creativas mediante las cuales puede dividir su lista en partes iguales.