190 votes

Longueur de la sortie du générateur

Python fournit une belle méthode pour obtenir la longueur d'un itérable eager, len(x) c'est-à-dire. Mais je n'ai rien trouvé de similaire pour les itérables paresseux représentés par des compréhensions de générateurs et des fonctions. Bien sûr, il n'est pas difficile d'écrire quelque chose comme :

def iterlen(x):
  n = 0
  try:
    while True:
      next(x)
      n += 1
  except StopIteration: pass
  return n

Mais je n'arrive pas à me débarrasser du sentiment que je réimplante un vélo.

(Pendant que je tapais la fonction, une pensée m'a traversé l'esprit : peut-être que cette fonction n'existe pas vraiment, car elle "détruit" son argument. Ce n'est pas un problème pour mon cas, cependant).

P.S. : concernant les premières réponses - oui, quelque chose comme len(list(x)) fonctionnerait aussi, mais cela augmente considérablement l'utilisation de la mémoire.

P.P.S. : revérifié... Ne tenez pas compte du P.S., il semble que j'ai fait une erreur en essayant cela, cela fonctionne bien. Désolé pour le dérangement.

0 votes

Suggérer un changement de titre en Longueur de la sortie du générateur SEULEMENT -- les éléments itérés peuvent être jetés. . Sinon, cette question est confondue avec un autre .

6 votes

reimplementing a bicycle - C'est presque comme réinventer la roue, sauf que c'est un programmeur qui l'a dit.

6voto

OlivierBlanvillain Points 1252

Utilice reduce(fonction, iterable[, initialisateur]) pour une solution purement fonctionnelle et efficace en termes de mémoire :

>>> iter = "This string has 30 characters."
>>> reduce(lambda acc, e: acc + 1, iter, 0)
30

0 votes

Vos chronologies sont fausses parce que l'itérateur est consommé. Seul le premier essai de len(list(iter)) itère réellement sur des valeurs quelconques, tous les autres comptent une séquence de longueur nulle. Dans mes tests, reduce est plus lent que len(list()) , enumerate y sum .

1 votes

@Blckknght Merci, corrigé.

5voto

pylang Points 12013

Essayez le more_itertools pour une solution simple. Exemple :

>>> import more_itertools

>>> it = iter("abcde")                                         # sample generator
>>> it
<str_iterator at 0x4ab3630>

>>> more_itertools.ilen(it)
5

Voir ce poste pour un autre exemple appliqué.

0voto

Yauhen Yakimovich Points 2222

D'ailleurs, si vous voulez vérifier si le générateur est vide il suffira de faire quelque chose comme :

def is_empty(generator):
    for item in generator:
        return False
    return True

0voto

yoniLavi Points 372

C'est un hack, mais si vous voulez vraiment avoir len sur un itérable général (en le consommant au passage), vous pouvez créer votre propre version de len .

El len est essentiellement équivalente à la fonction suivante (bien que les implémentations fournissent généralement des optimisations pour éviter la recherche supplémentaire) :

def len(iterable):
    return iterable.__len__()

Par conséquent, nous pouvons définir notre new_len pour essayer cela, et si __len__ n'existe pas, compter nous-mêmes le nombre d'éléments en consommant l'itérable :

def new_len(iterable):
    try:
      return iterable.__len__()
    except AttributeError:
      return sum(1 for _ in iterable)

Ce qui précède fonctionne en Python 2/3, et (pour autant que je sache) devrait couvrir tous les types d'itérables imaginables.

4 votes

Surcharger une fonction intégrée masquera le comportement original, ce qui rendra le code difficile (voire impossible) à déboguer. Vous devriez vraiment utiliser un nom différent pour la fonction qui ne doit pas être nommée len...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X