简体   繁体   中英

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 dict.get() . If we go the defaultdict route :

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

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

In [1225]: d
Out[1225]: 
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?

You just need a defaultdict(int) :

>>> from collections import defaultdict
>>>
>>> d = defaultdict(int)
>>> T = (('a', 'b', 2),
...  ('a', 'c', 4),
...  ('b', 'c', 1),
...  ('a', 'b', 8),) 
>>>
>>> for key1, key2, value in T:
...     d[(key1, key2)] += value
... 
>>> [(key1, key2, value) for (key1, key2), value in d.items()]
[
    ('b', 'c', 1), 
    ('a', 'b', 10), 
    ('a', 'c', 4)
]

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()])

print(T2)

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())

print(T2)

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()])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM