Suma wartości z listy, gdy warunek jest spełniony

głosy
1

Mam listę Pythona lzawierający wystąpienia klasy 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)]

Teraz chcę podsumować wszystkie valueczłonków klas Elements, jeśli ich idjest równa uzyskać tę listę:

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

Co jest najbardziej pythonic sposobem, aby to zrobić?

Utwórz 19/12/2018 o 14:11
źródło użytkownik
W innych językach...                            


3 odpowiedzi

głosy
6

Jest (prawie?) Nic, że itertoolsnie może zrobić. Spójrz na 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'))]

Co skutkuje w:

print(res)   # [Element(1, 300), Element(2, 1), Element(3, 8)]
Odpowiedział 19/12/2018 o 14:17
źródło użytkownik

głosy
2

Jednym ze sposobów byłoby stworzenie defaultdict, które odwzorowuje identyfikatory do sumy wartości. Wtedy możemy wziąć te wyniki i wykorzystać je do budowy nowej listy Elements. Jednym ze sposobów, aby to zrobić jest użycie starmapmapować elementy tego słownika do argumentówElement

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)]
Odpowiedział 19/12/2018 o 14:18
źródło użytkownik

głosy
1

Można również uzyskać pożądany efekt przy użyciu setdostać tylko unikalne identyfikatory i sumdo całkowitej wartości. Na przykład:

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)]
Odpowiedział 19/12/2018 o 14:36
źródło użytkownik

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