2013-11-26 3 views
8

Was ist der beste Weg, um diese einfache Funktion mit einem Listenverständnis (oder einem anderen kompakten Ansatz) zu replizieren?Listenverständnis mit einem Akkumulator

import numpy as np 

sum=0 
array=[] 
for i in np.random.rand(100): 
    sum+=i 
    array.append(sum) 
+0

Sie zufällig numpy verwenden? Ich weiß, dass numpy eine nette Funktion für so etwas hat. – arshajii

+1

Ich würde nicht ein Listenverständnis verwenden - Elemente werden erwartet, unabhängig voneinander zu sein, und in diesem Fall sind sie nicht. – Izkata

+1

Warum möchten Sie dies in ein Listenverständnis umwandeln? Es ist viel besser lesbar, dies in einer separaten Schleife zu halten. Machen Sie stattdessen 'array = [0] ',' für i in rand (100): array.append (i + array [-1]) '. –

Antwort

6

In Python 3, dann würden Sie verwenden itertools.accumulate():

from itertools import accumulate 

array = list(accumulate(rand(100))) 

Accumulate das laufende Ergebnis der Addition die Werte des Eingangs ergibt iterable, mit dem ersten Startwert:

>>> from itertools import accumulate 
>>> list(accumulate(range(10))) 
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45] 

Sie können eine andere Operation als zweites Argument übergeben; Dies sollte eine aufrufbare Funktion sein, die das akkumulierte Ergebnis und den nächsten Wert annimmt und das neue akkumulierte Ergebnis zurückgibt. Die operator module ist sehr hilfreich bei der Bereitstellung von mathematischen Standardoperatoren für diese Art von Arbeit; Sie könnten es verwenden, um einen Lauf zu erzeugen, zum Beispiel zur Folge Multiplikation:

>>> import operator 
>>> list(accumulate(range(1, 10), operator.mul)) 
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880] 

Die Funktionalität leicht genug, um ältere Versionen zu zurückzuportieren ist (Python 2 oder Python 3.0 oder 3.1):

# Python 3.1 or before 

import operator 

def accumulate(iterable, func=operator.add): 
    'Return running totals' 
    # accumulate([1,2,3,4,5]) --> 1 3 6 10 15 
    # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120 
    it = iter(iterable) 
    total = next(it) 
    yield total 
    for element in it: 
     total = func(total, element) 
     yield total 
+0

Dieser funktioniert, aber ich suchte nach einem Listenverständnis für den kompakten Gebrauch - wie in der ipython-Befehlszeile. – Pierz

+0

@Pierz: Ich habe 'list()' auf dem 'accumate()' Iterator verwendet, um Ihnen eine schnelle Liste von Werten zu geben. Sie können es auch in einem Listenverständnis verwenden, '[v für v in accumulate (rand (100))]'; Sie können dies jedoch nicht mit * nur * einem Listenverständnis tun, weil Sie keinen Zugriff auf die bisher erzeugten Elemente haben. –

+0

Wahr ist es eine elegante Annäherung, aber ich war nicht sicher, ob es einen ordentlichen Weg gab, die angesammelte Summe in einem Listenverständnis zu haben. Einverstanden, es ist wahrscheinlich nicht die beste Praxis, aber wenn Sie an der Befehlszeile arbeiten, ist es praktisch, kompakte Formulare zu verwenden. – Pierz

4

Da Sie sind bereits numpy verwenden, können Sie cumsum verwenden:

>>> from numpy.random import rand 
>>> x = rand(10) 
>>> x 
array([ 0.33006219, 0.75246128, 0.62998073, 0.87749341, 0.96969786, 
     0.02256228, 0.08539008, 0.83715312, 0.86611906, 0.97415447]) 
>>> x.cumsum() 
array([ 0.33006219, 1.08252347, 1.7125042 , 2.58999762, 3.55969548, 
     3.58225775, 3.66764783, 4.50480095, 5.37092001, 6.34507448]) 
1

Ok, Sie sagten, Sie nicht numpy wollte aber hier ist meine Lösung sowieso. Es scheint mir, dass Sie einfach die kumulative Summe nehmen, also verwenden Sie die cumsum() Funktion.

import numpy as np 
result = np.cumsum(some_array) 

Für ein willkürliches Beispiel

result = np.cumsum(np.random.uniform(size=100))