Reputation: 11
li=[('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]
Assuming I have this case. Where it starts with the same name in the first position, I want to add the second with the second and third with the third.
Desired result:
[('name1', 11, 13), ('name2', 3, 2)]
does anyone know how I can do this in Python?
Upvotes: 1
Views: 426
Reputation: 103844
Given:
LoT=[('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]
You can first use a dict to accumulate the like tags:
di={}
for t in LoT:
di.setdefault(t[0], []).append(t[1:])
>>> di
{'name1': [(5, 10), (6, 3)], 'name2': [(3, 2)]}
Then create a new list with the sum of those tags:
>>> [(k,)+tuple(map(sum, zip(*li))) for k,li in di.items()]
[('name1', 11, 13), ('name2', 3, 2)]
# the interesting thing here is the zip(*li) which rotates the list of tuples
# zip(*[(5, 10), (6, 3)]) => [(5, 6), (10, 3)]
Or, just keep a running total:
di={}
for t in LoT:
try:
di[t[0]]=tuple(map(sum, zip(di[t[0]], t[1:])))
except KeyError:
di[t[0]]=t[1:]
And then convert the running total dict to a list:
[(k,)+t for k,t in di.items()]
# same result
These solutions work regardless of the length of the tuples.
Upvotes: 0
Reputation: 145
Much simpler solution:
i = [('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]
d = {}
for name, fv, sv in i:
if name not in d:
d[name] = [name, fv, sv]
else:
d[name][1] += fv
d[name][2] += sv
[tuple(v) for v in d.values()]
Upvotes: 0
Reputation: 1247
Here is a method using class defintion:
class mytuple(object):
def __init__(self, tx, val1, val2):
self.tx = tx
self.val1 = val1
self.val2 = val2
def __add__(self, t2):
if self.tx != t2.tx :
print("WARNING: BAD TUPLE, ignoring", self.tx, t2.tx)
return mytuple(self.tx,
self.val1 + t2.val1,
self.val2 + t2.val2)
def __str__(self):
self.__repr()
def __repr__(self):
tstr = ', '.join([self.tx,
'%d'%self.val1,
'%d'%self.val2])
return('(%s)'%tstr)
arr = [ mytuple('name1', 5, 10),
mytuple('name2', 3, 2),
mytuple('name1', 6, 3)]
print([arr[0] + arr[2], arr[1]])
[(name1, 11, 13), (name2, 3, 2)]
Upvotes: 0
Reputation: 2348
Yet another answer, but with some built in flexibility:
li=[('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]
# Get length of structure
li_len = len(li)
# Create empty collection
outdict = {}
# Iterate over all elements
for i in range(li_len):
tmpname = li[i][0] # Temp name variable
tmpvalues = li[i][1:] # Temp values variable
# If not temp name in dictionary keys
if not tmpname in outdict:
# Create entry with values as first values
outdict[tmpname] = list(tmpvalues)
else:
# Otherwise, iterate values and update entry by position
for j in range(len(tmpvalues)):
outdict[tmpname][j] += tmpvalues[j]
# Reformat for output
result = [tuple([k] + v) for k, v in outdict.items()]
# Print result
print(result)
Output:
[('name1', 11, 13), ('name2', 3, 2)]
Upvotes: -1
Reputation: 153
Initially tuple's values cant be changed but if you want to do it the way you want then you could do something like this.
li = [['name1', 5, 10], ['name2', 3, 2], ['name1', 6, 3]]
new_li = []
for tup in li:
names = [tup[0] for tup in new_li]
if tup[0] in names:
index = names.index(tup[0])
new_li[index][1] += tup[1]
new_li[index][2] += tup[2]
else:
new_li.append(tup)
# [['name1', 11, 13], ['name2', 3, 2]]
# to make it tuple
new_li = [tuple(l) for l in new_li]
# [('name1', 11, 13), ('name2', 3, 2)]
Upvotes: 0
Reputation: 1247
You should define the tuple as a class. But if the data is given as a set of tuples... then define a function addTuple
.
def addTuple(t1, t2):
(ta,va1,va2) = t1
try: (ta,va1,va2) = t1
except:
# FIXME: default to None, value 0
(ta,va1, va2) = (None, 0, 0)
try:
# FIXME: default to None, value 0
(tb,vb1,vb2) = t2
except:
# FIXME: default to None, value 0
(tb,vb1, vb2) = (None, 0, 0)
return (ta, va1+vb1, va2+vb2)
print([addTuple(arr[0],arr[2]), addTuple(arr[1],0)])
[('name1', 1
Upvotes: 0
Reputation: 838
names = [('name1', 5, 10), ('name2', 3, 2), ('name1', 6, 3)]
### Iterate over all members of the original list to perform the logic
new_names = dict()
for n,first,second in names:
if n not in new_names:
new_names[n] = (first, second)
else:
new_names[n] = (first+new_names[n][0], second+new_names[n][1])
### Get back list of tuples
new_names2 = [(k, *v) for k,v in new_names.items()]
print(new_names2)
Output:
[('name1', 11, 13), ('name2', 3, 2)]
Upvotes: 0