¿Cómo tomar los primeros N elementos de un generador o lista en Python? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Con linq yo

var top5 = array.Take(5);

¿Cómo hacer esto con Python?

Author: guaka, 2011-03-08

8 answers

Cortar una lista

top5 = array[:5]
  • Para cortar una lista, hay una sintaxis simple: array[start:stop:step]
  • puede omitir cualquier parámetro. Todos estos son válidos: array[start:], array[:stop], array[::step]

Cortar un generador

 import itertools
 top5 = itertools.islice(my_list, 5) # grab the first five elements
  • No puedes dividir un generador directamente en Python. itertools.islice() envolverá un objeto en un nuevo generador de corte usando la sintaxis itertools.islice(generator, start, stop, step)

  • Recuerde, cortar un generador lo agotará parcialmente. Si quieres mantener todo el generador intacto, tal vez convertirlo en una tupla o lista primero, como: result = tuple(generator)

 340
Author: lunixbochs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-11 04:17:57
import itertools

top5 = itertools.islice(array, 5)
 97
Author: Jader Dias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-08 14:56:21

En mi gusto, también es muy conciso combinar 'zip()' con 'xrange(n)' (o 'range(n)' en Python3), que también funciona bien en generadores y parece ser más flexible para los cambios en general.

# Option #1: taking the first n elements as a list
[x for _, x in zip(xrange(n), generator)]

# Option #2, using 'next()' and taking care for 'StopIteration'
[next(generator) for _ in xrange(n)]

# Option #3: taking the first n elements as a new generator
(x for _, x in zip(xrange(n), generator))

# Option #4: yielding them by simply preparing a function
# (but take care for 'StopIteration')
def top_n(n, generator):
    for _ in xrange(n): yield next(generator)
 29
Author: Shaikovsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-01 19:46:27

La respuesta de@Shaikovsky es excelente, pero quería aclarar un par de puntos.

[next(generator) for _ in range(n)]

Este es el enfoque más simple, pero arroja StopIteration si el generador se agota prematuramente.


Por otro lado, los siguientes enfoques devuelven hasta n items which is arguably preferable in most circumstances:

Lista: [x for _, x in zip(range(n), records)]

Generador: (x for _, x in zip(range(n), records))

 14
Author: Bede Constantinides,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-06 19:40:27

La respuesta para hacer esto se puede encontrar aquí

>>> generator = (i for i in xrange(10))
>>> list(next(generator) for _ in range(4))
[0, 1, 2, 3]
>>> list(next(generator) for _ in range(4))
[4, 5, 6, 7]
>>> list(next(generator) for _ in range(4))
[8, 9]

Observe que la última llamada pide los siguientes 4 cuando solo quedan 2. El uso de list() en lugar de [] es lo que hace que la comprensión termine en la excepción StopIteration que es lanzada por next().

 9
Author: ebergerson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:47

¿Te refieres a los primeros N elementos, o los N más grandes elementos?

Si quieres el primero:

top5 = sequence[:5]

Esto también funciona para los N elementos más grandes, suponiendo que su secuencia esté ordenada en orden descendente. (Su ejemplo de LINQ parece asumir esto también.)

Si quieres el más grande, y no está ordenado, la solución más obvia es ordenarlo primero:

l = list(sequence)
l.sort(reverse=True)
top5 = l[:5]

Para una solución más eficiente, utilice un min-heap (Thijs gracias):

import heapq
top5 = heapq.nlargest(5, sequence)
 5
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 19:14:13

Con itertools obtendrá otro objeto generador por lo que en la mayoría de los casos necesitará otro paso para tomar los primeros N elementos (N). Hay al menos dos soluciones más simples (un poco menos eficientes en términos de rendimiento, pero muy útiles) para obtener los elementos listos para usar de un generator:

Usando la comprensión de lista:

first_N_element=[generator.next() for i in range(N)]

De lo contrario:

first_N_element=list(generator)[:N]

Donde N es el número de elementos que desea tomar (por ejemplo, N=5 para los primeros cinco elementos).

 3
Author: G M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-07 11:17:41

Esto debería funcionar

top5 = array[:5] 
 -4
Author: Bala R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-08 14:57:41