Comment prendre les N premiers éléments d'un générateur ou d'une liste en Python? [dupliquer]
8 réponses
trancher une liste
top5 = array[:5]
- pour trancher une liste, il y a une syntaxe simple:
array[start:stop:step]
- vous pouvez omettre n'importe quel paramètre. Ils sont tous valables.:
array[start:]
,array[:stop]
,array[::step]
couper une génératrice
import itertools
top5 = itertools.islice(my_list, 5) # grab the first five elements
-
vous ne pouvez pas couper un générateur directement en Python.
itertools.islice()
s'occupera de l'emballage un objet dans un nouveau générateur de tranchage utilisant la syntaxeitertools.islice(generator, start, stop, step)
-
rappelez-vous, couper une génératrice l'épuisera en partie. Si vous voulez garder la génératrice entière intacte, peut-être la transformer en un tuple ou la liste d'abord, comme:
result = tuple(generator)
à mon goût, il est également très concis de combiner 'zip()' avec 'xrange(n)' (ou 'range(n)' en Python3), ce qui fonctionne bien sur les générateurs et semble être plus flexible pour les changements en général.
# 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)
la réponse de @Shaikovsky est excellente, mais je voulais clarifier quelques points.
[next(generator) for _ in range(n)]
c'est l'approche la plus simple, mais lance StopIteration
si le générateur est prématurément épuisé.
d'autre part, les approches suivantes renvoient jusqu'à n
éléments qui sont sans doute préférables dans la plupart des circonstances:
liste:
[x for _, x in zip(range(n), records)]
générateur:
(x for _, x in zip(range(n), records))
la réponse à cette question se trouve ici
>>> 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]
noter que le dernier appel demande pour les 4 prochains alors qu'il ne reste que 2. L'utilisation du list()
au lieu de []
est ce qui fait que la compréhension se termine sur l'exception StopIteration
qui est lancée par next()
.
voulez-vous dire le premier N articles, ou le N plus grand articles?
si vous voulez le premier:
top5 = sequence[:5]
cela fonctionne également pour les plus grands N articles, en supposant que votre séquence est triée dans l'ordre décroissant. (Votre exemple de LINQ semble le supposer aussi.)
si vous voulez le plus grand, et il n'est pas trié, la solution la plus évidente est de le trier d'abord:
l = list(sequence)
l.sort(reverse=True)
top5 = l[:5]
pour une solution plus performante, utilisez un Min-heap (merci Thijs):
import heapq
top5 = heapq.nlargest(5, sequence)
avec itertools
vous obtiendrez un autre objet générateur donc dans la plupart des cas vous aurez besoin d'une autre étape la prise des premiers éléments N ( N
). Il existe au moins deux solutions plus simples (un peu moins efficaces en termes de performances mais très pratiques) pour obtenir les éléments prêts à l'emploi à partir d'un generator
:
à l'Aide de la liste de compréhension:
first_N_element=[generator.next() for i in range(N)]
sinon:
first_N_element=list(generator)[:N]
où N
est le nombre d'éléments que vous voulez prendre (par exemple N=5 pour les cinq premiers éléments).