Somme des valeurs dans la liste lorsque la condition est remplie

voix
1

J'ai une liste python lcontenant des instances de la classe Element:

class Element:
    def __init__(self, id, value):
        self.id = id
        self.value = value

l = [Element(1, 100), Element(1, 200), Element(2, 1), Element(3, 4), Element(3, 4)]

Maintenant , je veux résumer tous les valuemembres des classes Elementssi leur idest égal à obtenir cette liste:

l = [Element(1, 300), Element(2, 1), Element(3, 8)]

Quelle est la manière la plus pythonique de le faire?

Créé 19/12/2018 à 14:11
source utilisateur
Dans d'autres langues...                            


3 réponses

voix
6

Il n'y a rien (presque?) Qui itertoolsne peut pas faire. Jetez un oeil à groupby:

from itertools import groupby
from operator import attrgetter


class Element:
    def __init__(self, id, value):
        self.id = id
        self.value = value
    def __repr__(self):  # kudos @mesejo
        return "Element({}, {})".format(self.id, self.value)

l = [Element(1, 100), Element(1, 200), Element(2, 1), Element(3, 4), Element(3, 4)]

l.sort(key=attrgetter('id'))  # if it is already sorted by 'id', comment-out

res = [Element(g, sum(sub.value for sub in k)) for g, k in groupby(l, key=attrgetter('id'))]

qui se traduit par:

print(res)   # [Element(1, 300), Element(2, 1), Element(3, 8)]
Créé 19/12/2018 à 14:17
source utilisateur

voix
2

Une façon serait de créer une defaultdictqui mappe ids sommes des valeurs. Ensuite , nous pouvons prendre ces résultats et de les utiliser pour construire une nouvelle liste de Elements. Une façon de le faire est d'utiliser starmappour cartographier les éléments de ce dictionnaire aux argumentsElement

from collections import defaultdict
from itertools import starmap

class Element:
    def __init__(self, id, value):
        self.id = id
        self.value = value
    def __repr__(self):
        return "Element({}, {})".format(self.id, self.value)

l = [Element(1, 100), Element(1, 200), Element(2, 1), Element(3, 4), Element(3, 4)]

d = defaultdict(int)

for e in l:
    d[e.id] += e.value

print(list(starmap(Element, d.items())))
# [Element(1, 300), Element(2, 1), Element(3, 8)]
Créé 19/12/2018 à 14:18
source utilisateur

voix
1

Vous pouvez également obtenir le résultat souhaité à l' aide setpour obtenir seulement les ids uniques et sumtotaliser les valeurs. Par exemple:

class Element:
    def __init__(self, id, value):
        self.id = id
        self.value = value

l = [Element(1, 100), Element(1, 200), Element(2, 1), Element(3, 4), Element(3, 4)]

ids = set(elem.id for elem in l)
totals = [Element(i, sum(elem.value for elem in l if elem.id == i)) for i in ids]
# [Element(1, 300), Element(2, 1), Element(3, 8)]
Créé 19/12/2018 à 14:36
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more