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
surcount_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.
Vous devez vous connecter pour publier un commentaire.
À l'aide des nombres complexes
1j
n'est pas une faute de frappe?1j
pour chaque élément, vous êtes incremeting l'irrationnel partie du nombre complexe; par conséquent, vous êtes à l'aide de la irraitonal partie comme un compteur, tandis que la partie réelle détient la somme des nombres réels.Trignometry
Complex Numbers
dans sonMath
classe 🙂sum(map(1j.__add__(z))
.Je ne sais pas à propos de la vitesse, mais c'est le genre de jolie:
if not col.hide
, qui manque dans le dernier exemple.accumulate
peut ne pas être en mesure de gérer.accumulate(col.width for col in cols if not col.hide)
,accumulate
ne pas le voir, beaucoup moins de soins, sur ce qui se passe à l'intérieur.Adaptation de DSM réponse. à l'aide de
deque(... maxlen=1)
pour économiser de l'utilisation de la mémoire.code de timing dans ipython:
résultats: maintenant plus rapide que l'OP de la méthode
max
ne pas allouer de la mémoire pour la liste. À tout instant seulement deux tuples sont stockées, celui que vous êtes en train de regarder et le dernier maximum. Je pense qu'il faut juste que le deque la mise en œuvre est très rapide et/ou le n-uplet de comparaison est lente.max
donner la valeur faux si le dernier élément négatif? La deuxième à la dernière éléments pourrait être plus grande, alors le dernierenumerate
, souvenez-vous-sont toujours de la forme(i, value)
et(i+1, next_value)
. Les valeurs ne viennent jamais en jouer parce qu'il décide de toujours qui est plus basé sur le premier élément, l'index.Voici quelques données de temps qui pourrait être d'intérêt:
Résultat:
Compte tenu de ces résultats, je ne suis pas vraiment sûr de savoir comment les OP, c'est de voir une 100x ralentissement avec l'un passage de la méthode. Même si les données semblent radicalement différentes à partir d'une liste d'entiers aléatoires, qui ne doivent pas se produire.
Aussi, M4rtini la solution ressemble le gagnant clair.
À préciser, ces résultats sont en Disponible 3.2.3. Pour une comparaison à PyPy3, voir James_pic réponse, qui montre le peu de sérieux gains de compilation JIT pour certaines méthodes (également mentionné dans un commentaire par M4rtini.
functional
méthode, initialiser deux variables danscount_and_sum
méthode etc. Mais, comme votre résultats suggèrent, ils sont trop petit pour influencer le résultat.count_and_sum
être un appel de fonction, lasum(genexp)
formulaire a été exécutée directement dans latimeit
param, qui est la façon dont il serait fait dans mon projet de code. Vos résultats, bien qu'informative, ne pas tenir compte de la façon dont le code final serait exécuté.Comme un suivi de
senshin
's réponse, il est intéressant de noter que les différences de performances sont en grande partie en raison de bizarreries dans Disponible de la mise en œuvre, qui font que certaines méthodes sont plus lents que d'autres (par exemple,for
boucles sont relativement lent en Disponible). J'ai pensé qu'il serait intéressant d'essayer de le exactement le même test dans PyPy (à l'aide de PyPy3 2.1 beta), qui a des caractéristiques de performance différentes. Dans PyPy les résultats sont les suivants:Dans ce cas, l'OP est un passe-méthode est la plus rapide. Cela est logique, car c'est sans doute le plus simple (au moins à partir d'un compilateur de point de vue) et PyPy pouvez éliminer la plupart des frais généraux par l'in-lining appels de méthode, qui Disponible ne le peuvent pas.
À des fins de comparaison, Disponible 3.3.2 sur ma machine donne les éléments suivants:
Vous pouvez compter à l'intérieur de la somme avec des astuces similaires à ce
Mais ça va probablement être plus lisible d'utiliser une boucle for
cnt - 1
à la fin...next(cnt)*0 or x
devrait également fonctionner. Ou même~next(cnt) and x
Vous pouvez utiliser ceci:
C'est une sorte de hack, mais il fonctionne parfaitement bien.
Je ne sais pas ce que la syntaxe de Python est éteint à la main, mais vous pouvez éventuellement utiliser un pli. Quelque chose comme ceci:
L'idée est d'utiliser une semence de (0,0) et puis à chaque étape, ajouter 1 à la première composante et le nombre actuel pour le second volet.
À des fins de comparaison, vous pouvez mettre en œuvre
sum
comme un pli comme suit:reduce(lambda pair, x: (pair[0]+1, pair[1]+x), a, (0,0))
après l'importationfunctools.reduce
.1_CR du nombre complexe solution est mignon mais trop hacky. La raison pour laquelle il travaille est qu'un nombre complexe est un 2-tuple, qui sommes elementwise. La même chose est vraie de tableaux numpy et je pense que c'est légèrement plus propre à l'utilisation de ces:
Autre chose à prendre en compte: Si il est possible de déterminer un minimum possible de comptage, nous pouvons laisser l'efficacité de l'intégré dans
sum
effectuer une partie du travail:Par exemple, à l'aide de la
deque
méthode avec une séquence de 10000000 éléments etmin_count
de 5000000 de timing, les résultats sont les suivants:Comment à ce sujet?
Il semble fonctionner.
Vous pourriez seulement besoin de la somme & compter d'aujourd'hui, mais qui sait ce dont vous aurez besoin demain!
Voici un facilement extensible solution:
Merci pour toutes ces excellentes réponses, mais j'ai décidé d'utiliser mon original
count_and_sum
fonction, appelée comme suit:Comme expliqué dans les modifications apportées à ma question de départ, cela s'est avéré pour être le plus rapide et le plus lisible solution.