Pyderman Pyderman - 11 months ago 26
Python Question

Summing similar elements within a tuple-of-tuples

Following on from this question, I now need to sum similar entries (tuples) within an overall tuple.

So given a tuple-of-tuples such as:

T = (('a', 'b', 2),
('a', 'c', 4),
('b', 'c', 1),
('a', 'b', 8),)

For all tuples where the first and second element are identical, I want to sum the third element, otherwise, leave the tuple in place. So I will end up with the following tuple-of-tuples:

(('a', 'b', 10),
('a', 'c', 4),
('b', 'c', 1),)

The order of the tuples within the enclosing tuple (and the summing) doesn't matter.

We are dealing with tuples so we can't take advantage of something like
. If we go the
route :

In [1218]: d = defaultdict(lambda: defaultdict(int))

In [1220]: for t in T:
d[t[0]][t[1]] += t[2]

In [1225]: d
defaultdict(<function __main__.<lambda>>,
{'a': defaultdict(int, {'b': 10, 'c': 4}),
'b': defaultdict(int, {'c': 1})})

I'm not quite sure how to reconstruct that into a tuple-of-tuples. Any anyway, although the order of the three elements within each tuple will be consistent, I'm not comfortable with my indexing of the tuples. Can this be done without any conversion to other data types?


Code -

from collections import defaultdict

T1 = (('a', 'b', 2),
 ('a', 'c', 4),
 ('b', 'c', 1),
 ('a', 'b', 8),)

d = defaultdict(int)

for x, y, z in T1:
    d[(x, y)] += z

T2 = tuple([(*k, v) for k, v in d.items()])


Output -

(('a', 'c', 4), ('b', 'c', 1), ('a', 'b', 10))

If you're interested in maintaining the original order, then -

from collections import OrderedDict

T1 = (('a', 'b', 2), ('a', 'c', 4), ('b', 'c', 1), ('a', 'b', 8),)

d = OrderedDict()

for x, y, z in T1:
    d[(x, y)] = d[(x, y)] + z if (x, y) in d else z

T2 = tuple((*k, v) for k, v in d.items())


Output -

(('a', 'b', 10), ('a', 'c', 4), ('b', 'c', 1))

In Python 2, you should use this -

T2 = tuple([(x, y, z) for (x, y), z in d.items()])