Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Estoy buscando una manera rápida, de forma limpia, Pythonic para dividir una lista en casi exactamente n-igualdad de particiones.

partition([1,2,3,4,5],5)->[[1],[2],[3],[4],[5]]
partition([1,2,3,4,5],2)->[[1,2],[3,4,5]] (or [[1,2,3],[4,5]])
partition([1,2,3,4,5],3)->[[1,2],[3,4],[5]] (there are other ways to slice this one too)

Hay varias respuestas de aquí iteración sobre la lista rebanadas que se ejecutan muy cerca de lo que desee, excepto que se centran en el tamaño de la lista, y me importa el número de las listas (algunos de ellos también pad con ninguno). Estos se convierten trivialmente, obviamente, pero estoy buscando una mejor práctica.

Del mismo modo, las personas han señalado grandes soluciones aquí ¿Cómo dividir una lista en trozos de tamaño uniforme? para un problema muy similar, pero estoy más interesado en el número de particiones que el tamaño específico, siempre y cuando sea dentro de 1. de nuevo, esto es trivialmente convertible, pero estoy buscando una mejor práctica.

¿Fue útil?

Solución

def partition(lst, n):
    division = len(lst) / float(n)
    return [ lst[int(round(division * i)): int(round(division * (i + 1)))] for i in xrange(n) ]

>>> partition([1,2,3,4,5],5)
[[1], [2], [3], [4], [5]]
>>> partition([1,2,3,4,5],2)
[[1, 2, 3], [4, 5]]
>>> partition([1,2,3,4,5],3)
[[1, 2], [3, 4], [5]]
>>> partition(range(105), 10)
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], [32, 33, 34, 35, 36, 37, 38, 39, 40, 41], [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52], [53, 54, 55, 56, 57, 58, 59, 60, 61, 62], [63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73], [74, 75, 76, 77, 78, 79, 80, 81, 82, 83], [84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94], [95, 96, 97, 98, 99, 100, 101, 102, 103, 104]]

Python 3 version:

def partition(lst, n):
    division = len(lst) / n
    return [lst[round(division * i):round(division * (i + 1))] for i in range(n)]

Otros consejos

Sólo un punto de vista diferente, que sólo funciona si [[1,3,5],[2,4]] es una partición aceptable, en su ejemplo.

def partition ( lst, n ):
    return [ lst[i::n] for i in xrange(n) ]

Esto satisface el ejemplo mencionado en el ejemplo de @ Daniel Stutzbach:

partition(range(105),10)
# [[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
# [1, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101],
# [2, 12, 22, 32, 42, 52, 62, 72, 82, 92, 102],
# [3, 13, 23, 33, 43, 53, 63, 73, 83, 93, 103],
# [4, 14, 24, 34, 44, 54, 64, 74, 84, 94, 104],
# [5, 15, 25, 35, 45, 55, 65, 75, 85, 95],
# [6, 16, 26, 36, 46, 56, 66, 76, 86, 96],
# [7, 17, 27, 37, 47, 57, 67, 77, 87, 97],
# [8, 18, 28, 38, 48, 58, 68, 78, 88, 98],
# [9, 19, 29, 39, 49, 59, 69, 79, 89, 99]]

Aquí hay una versión que es similar a la de Daniel: divide lo más uniformemente posible, pero pone todas las particiones más grandes en el inicio:

def partition(lst, n):
    q, r = divmod(len(lst), n)
    indices = [q*i + min(i, r) for i in xrange(n+1)]
    return [lst[indices[i]:indices[i+1]] for i in xrange(n)]

También se evita el uso de la aritmética flotante, ya que siempre me hace incómodo. :)

Editar: un ejemplo, sólo para mostrar el contraste con la de Daniel Stutzbach solución

>>> print [len(x) for x in partition(range(105), 10)]
[11, 11, 11, 11, 11, 10, 10, 10, 10, 10]

A continuación se muestra una forma.

def partition(lst, n):
    increment = len(lst) / float(n)
    last = 0
    i = 1
    results = []
    while last < len(lst):
        idx = int(round(increment * i))
        results.append(lst[last:idx])
        last = idx
        i += 1
    return results

Si len (LST) no puede ser uniformemente dividido por n, esta versión va a distribuir los artículos adicionales a intervalos más o menos iguales. Por ejemplo:

>>> print [len(x) for x in partition(range(105), 10)]
[11, 10, 11, 10, 11, 10, 11, 10, 11, 10]

El código puede ser más sencillo si no te importa todos los 11s siendo al principio o al final.

Esta respuesta proporciona una función split(list_, n, max_ratio), para las personas quien desee dividir su lista en pedazos n con un máximo de max_ratio relación en la pieza de longitud. Permite una mayor variación de la interrogador de 'a lo sumo 1 diferencia en la pieza de longitud'.

Funciona mediante el muestreo de n pieza longitudes dentro del intervalo de relación deseado [1, max_ratio) , colocándolos después entre sí para formar un 'roto palo' con las distancias correctas entre los puntos de ruptura '', pero el mal largo total. Escalar el palo roto a la longitud deseada nos da las posiciones aproximadas de los puntos de quiebre que queremos. Para llegar entero puntos de ruptura requiere redondeo subsiguiente.

Por desgracia, los redondeos puede conspiran para hacer sólo piezas demasiado corto, y dejar que se excede el max_ratio. Ver la parte inferior de esta respuesta para una ejemplo.

import random

def splitting_points(length, n, max_ratio):
    """n+1 slice points [0, ..., length] for n random-sized slices.

    max_ratio is the largest allowable ratio between the largest and the
    smallest part.
    """
    ratios = [random.uniform(1, max_ratio) for _ in range(n)]
    normalized_ratios = [r / sum(ratios) for r in ratios]
    cumulative_ratios = [
        sum(normalized_ratios[0:i])
        for i in range(n+1)
    ]
    scaled_distances = [
        int(round(r * length))
        for r in cumulative_ratios
    ]

    return scaled_distances


def split(list_, n, max_ratio):
    """Slice a list into n randomly-sized parts.

    max_ratio is the largest allowable ratio between the largest and the
    smallest part.
    """

    points = splitting_points(len(list_), n, ratio)

    return [
        list_[ points[i] : points[i+1] ]
        for i in range(n)
    ]

Se puede probar que fuera de esta manera:

for _ in range(10):
    parts = split('abcdefghijklmnopqrstuvwxyz', 4, 2)
    print([(len(part), part) for part in parts])

Ejemplo de un mal resultado:

parts = split('abcdefghijklmnopqrstuvwxyz', 10, 2)

# lengths range from 1 to 4, not 2 to 4
[(3, 'abc'),  (3, 'def'), (1, 'g'),
 (4, 'hijk'), (3, 'lmn'), (2, 'op'),
 (2, 'qr'),  (3, 'stu'),  (2, 'vw'),
 (3, 'xyz')]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top