Besoin d'un moyen rapide de compter et de faire la somme d'un itérable en un seul passage

Quelqu'un peut-il m'aider? J'essaie de trouver un moyen pour calculer

>>> sum_widths = sum(col.width for col in cols if not col.hide)

et de compter le nombre d'éléments dans cette somme, sans avoir à faire deux passes de plus de cols.

Il semble incroyable, mais après le balayage mst-lib (fonctions intégrées, itertools, functools, etc), je ne pouvais même pas trouver une fonction qui compte le nombre de membres dans un objet iterable. J'ai trouvé la fonction itertools.count, qui sonne comme ce que je veux, mais C'est vraiment juste un air faussement nommé range fonction.

Après un peu de réflexion, je suis venu avec la suivante (qui est si simple que l'absence d'une fonction de la bibliothèque peut être excusable, à l'exception de sa obtuseness):

>>> visable_col_count = sum(col is col for col in cols if not col.hide)

Cependant, l'utilisation de ces deux fonctions nécessite deux passages de l'itératif, qui vient de me frotte le mauvais sens.

Comme une alternative, la fonction suivante est ce que je veux:

>>> def count_and_sum(iter):
>>>     count = sum = 0
>>>     for item in iter:
>>>         count += 1
>>>         sum += item
>>>     return count, sum

Le problème, c'est qu'il faut 100 fois plus longtemps (selon timeit) comme la somme d'un générateur de forme d'expression.

Si quelqu'un peut venir avec un simple one-liner qui fait ce que je veux, s'il vous plaît laissez-moi savoir (à l'aide de Python 3.3).

Edit 1

Beaucoup de bonnes idées ici, les gars. Merci à tous ceux qui ont répondu. Il va me prendre un certain temps pour digérer toutes ces réponses, mais je le ferai, et je vais essayer de chercher un pour vérifier.

Edit 2

J'ai répété les horaires sur mes deux humbles suggestions (count_and_sum de la fonction et de séparer les 2 sum fonctions) et découvert que mon timing était, probablement en raison d'une auto-sauvegarde planifiée processus en cours d'exécution en arrière-plan.

J'ai également chronométré la plupart des excellentes suggestions étant donné que des réponses ici, tous avec le même modèle. L'analyse de ces réponses a été toute une éducation pour moi: de nouvelles utilisations pour deque, enumerate et reduce et première fois pour count et accumulate. Merci à tous!

Voici les résultats (à partir de mon lent netbook) en utilisant le logiciel, je suis en développement pour l'affichage:

┌───────────────────────────────────────────────────────┐
                 Count and Sum Timing                  
├──────────────────────────┬───────────┬────────────────┤
          Method          Time (usec)│Time (% of base)│
├──────────────────────────┼───────────┼────────────────┤
count_and_sum (base)              7.2            100%│
Two sums                          7.5            104%│
deque enumerate accumulate        7.3            101%│
max enumerate accumulate          7.3            101%│
reduce                            7.4            103%│
count sum                         7.3            101%│
└──────────────────────────┴───────────┴────────────────┘

(Je n'ai pas le temps de la complexité et de plier les méthodes comme étant tout simplement trop obscure, mais merci quand même.)

Puisqu'il y a très peu de différence de timing entre toutes ces méthodes, j'ai décidé d'utiliser le count_and_sum fonction (explicite for boucle) comme étant le plus lisible, explicite et simple (Python Zen) et il arrive aussi d'être le plus rapide!

Je souhaite que je pourrais accepter l'une de ces étonnantes réponses correctes, mais ils sont tout aussi bon mais plus ou moins obscur, je suis juste en haut à droit de vote de tout le monde et accepter ma propre réponse comme correcte (count_and_sum fonction) puisque c'est ce que j'utilise.

Qu'était-ce à propos de "Il devrait y avoir un, et de préférence seulement une façon évidente de le faire."?

  • Vous vous rendez compte que, si votre timing que l'information est exacte, la passe de deux "frotte le mauvais chemin", la solution est 50 fois plus vite que l'autre? Parfois, il vaut mieux être pragmatique 🙂
  • Il y a des situations dans lesquelles vous ne voulez pas à la parcourir deux fois, comme lorsque le générateur est coûteux.
  • Je suis entièrement d'passionnés en général, mais ce n'est évidemment pas un de ces cas, étant donné les horaires prévus. Je n'aime pas faire les choses deux fois, soit, mais, si l'alternative est de le faire une fois et plus lent (n'ayant pas d'autres avantages), je vais choisir le pragmatisme plus de dogmatisme 🙂
  • La fonction ne doit pas prendre 100 fois plus longtemps! Quelque chose d'étrange se passe là-bas.
  • j'ai peut-être raté quelque chose embarrassante évident. mais pourquoi ne pas sum(iter), len(iter) ?
  • Vos deux premiers échantillons ont une condition supplémentaire if not col.hide, mais qui est absent dans l' count_and_sum. Pourquoi donc?
  • J'avais l'intention count_and_sum plus général de la fonction et de l'appeler comme: count, sum = count_and_sum(col.width for col in cols if not col.hide) mais maintenant que je l'ai écrit, je vois l'erreur de mon plan. Merci pour ça.
  • Exactement. Ce programme est d'oublier une pièce essentielle de l'information. Veuillez les corriger. Et DSM accumulate semble bon.
  • Pourriez-vous poster un peu comment vous êtes arrivé à l'100x ralentissement de la figure? La précision de commande/code que vous avez utilisé serait l'idéal. 100x ralentissement ne sent pas bon pour ce code.
  • Gifles @numba.autojit sur count_and_sum fait qu'il est aussi rapide que la deque méthode. L'ajout inn un peu de logique pour le filtrage conditionnel et l'ajout de numba dans le mélange, pourrait être tout à fait bon.