1
votes

Obtenez les sommes correspondantes des parties d'une liste

J'ai une liste [0, 1, 2, 3, 4, 5, 6] et je additionne ses parties pour que:

l = [0, 1, 2, 3, 4, 5, 6] -> 21

l = [1, 2, 3, 4, 5, 6] -> 21

l = [2, 3, 4, 5, 6] -> 20

l = [3, 4, 5, 6] -> 18

l = [4, 5, 6] -> 15

l = [5, 6] -> 11

l = [6] -> 6

l = [] -> 0

Donc, J'obtiens les sommes correspondantes des parties de la liste: [21, 21, 20, 18, 15, 11, 6, 0]

Le code que j'utilise est: p >

[somme (l [i:]) pour i dans la plage (len (l) + 1)]

Mais, pour les listes avec une plage supérieure à 100000 le code ralentit considérablement.

Une idée pourquoi et comment l'optimiser?


3 commentaires

vous réutilisez des valeurs précalculées. Je vous suggère d'utiliser la somme cumulative


Chaque fois que vous calculez une nouvelle somme - alors que les sommes se chevauchent. Comptez à partir du dernier élément, manuellement ou en utilisant la somme cumulée de la liste.


np.cumsum .


3 Réponses :


1
votes

Pour autant que je sache, il n'y a pas de moyen propre de le faire avec des compréhensions de liste.

Ce code fonctionnera sans aucune autre bibliothèque:

[(x, total := total + x) for x in items]

À partir de Python 3.8 sur, il y a un nouvel opérateur qui pourrait aider:

def cumulative_sum(a):
  total= 0
  for item in a:
    total += item
    yield total

list(cumulative_sum(listname))


1 commentaires

C'est l'opérateur du morse!



8
votes

Je suggérerais itertools.accumulate pour cela (que je rappelle est plus rapide que np.cumsum ), avec une liste inversée pour obtenir la sortie souhaitée:

>>> from itertools import accumulate
>>> lst = [0, 1, 2, 3, 4, 5, 6]
>>> list(accumulate(reversed(lst)))[::-1]
[21, 21, 20, 18, 15, 11, 6]

(vous pouvez facilement ajouter 0 à la fin si nécessaire )


0 commentaires

7
votes

Cela peut aider à réduire le temps de calcul pour les grandes listes:

from timeit import timeit

def sum10(l):
    from itertools import accumulate
    return list(accumulate(reversed(l)))[::-1]+[0]

def sum11(l):
    from itertools import accumulate
    return list(accumulate(l[::-1]))[::-1]+[0]


def sum20(l):
    from numpy import cumsum
    return list(cumsum(l[::-1]))[::-1]+[0]

def sum21(l):
    from numpy import cumsum
    return list(cumsum(list(reversed(l))))[::-1]+[0]

l = list(range(1000000))
iter_0 = timeit(lambda: sum10(l), number=10)  #0.14102990700121154
iter_1 = timeit(lambda: sum11(l), number=10)  #0.1336850459993002
nump_0 = timeit(lambda: sum20(l), number=10)  #0.6019859320003889
nump_1 = timeit(lambda: sum21(l), number=10)  #0.3818727100006072

Sortie :

[21, 21, 20, 18, 15, 11, 6, 0]

Ici est une comparaison des performances pour quatre méthodes différentes, qui font toutes la même chose:

l = [0, 1, 2, 3, 4, 5, 6]
output = list(np.cumsum(l[::-1]))[::-1]+[0]


2 commentaires

+ l [0] n'est pas la bonne chose à faire ici, je pense qu'ils signifient +0 toujours même si la liste ne commence pas par 0


De plus, je ne peux pas du tout reproduire vos horaires sur ipython pastebin.com/x3U1q0nZ