adding tuple elements in a list - python

l1=[(2,1),(3,2),(4,5)]
l2=[(2,3),(3,6),(11,3)]
I need:
result=[(2,4),(3,8),(4,5),(11,3)]
using for loop I was able to add tuples having the same first element.
>>> result = []
l1 = [(2, 1), (3, 2), (4, 5)]
l2 = [(2, 3), (3, 6), (11, 3)]
for x, y in l1:
for p, q in l2:
if x == p:
result.append((x, (y + q)))
>>> result
[(2, 4), (3, 8)]
How do I further add (4,5),(11,3)

So many ways to achieve the same goal... I like it!
Here is my solution.
l1=[(2,1),(3,2),(4,5)]
l2=[(2,3),(3,6),(11,3)]
d1 = dict(l1)
d2 = dict(l2)
result = []
for k in d1:
if k in d2:
result.append((k,d1[k]+d2[k]))
else:
result.append((k,d1[k]))
for k in d2:
if k not in d1:
result.append((k,d2[k]))
>>>print result
[(2, 4), (3, 8), (4, 5), (11, 3)]

There's no need to go through the elements of l2 for all elements of l1 if I understand what you're going for. Just use zip (or izip_longest if the lists have an uneven size) to use a tuple from each list and then append the first item and the sum if the first item matches and extend both tuples if they don't:
for tup1, tup2 in zip(l1, l2):
if tup1[0] == tup2[0]:
result.append((tup1[0], (tup1[1] + tup2[1])))
else:
result.extend([tup1, tup2])
With your input, this returns the required output:
>>> result
... [(2, 4), (3, 8), (4, 5), (11, 3)]

It can be easily done by using dict formed with l1 and iterating over l2, see working code snippet below:
l1=[(2,1),(3,2),(4,5)]
l2=[(2,3),(3,6),(11,3)]
result = dict(l1)
for y in l2:
result[y[0]] = result.get(y[0],0) + y[1]
result = result.items()
print result #[(11, 3), (2, 4), (3, 8), (4, 5)]
Or simply build results by iterating over concatenation of l1 and l2:
l1=[(2,1),(3,2),(4,5)]
l2=[(2,3),(3,6),(11,3)]
result = {}
for item in l1 + l2:
result[item[0]] = result.get(item[0],0) + item[1]
Good luck!

Seems natural to use a dictionary to keep track of which keys are already used. You can reduce the code size by using defaultdict:
import collections
l1=[(2,1),(3,2),(4,5)]
l2=[(2,3),(3,6),(11,3)]
d = collections.defaultdict(int)
for x,y in l1 + l2:
d[x] += y
print sorted(d.items())

Related

Sort out pairs with same members but different order from list of pairs

From the list
l =[(3,4),(2,3),(4,3),(3,2)]
I want to sort out all second appearances of pairs with the same members in reverse order. I.e., the result should be
[(3,4),(2,3)]
What's the most concise way to do that in Python?
Alternatively, one might do it in a more verbose way:
l = [(3,4),(2,3),(4,3),(3,2)]
L = []
omega = set([])
for a,b in l:
key = (min(a,b), max(a,b))
if key in omega:
continue
omega.add(key)
L.append((a,b))
print(L)
If we want to keep only the first tuple of each pair:
l =[(3,4),(2,3),(4,3),(3,2), (3, 3), (5, 6)]
def first_tuples(l):
# We could use a list to keep track of the already seen
# tuples, but checking if they are in a set is faster
already_seen = set()
out = []
for tup in l:
if set(tup) not in already_seen:
out.append(tup)
# As sets can only contain hashables, we use a
# frozenset here
already_seen.add(frozenset(tup))
return out
print(first_tuples(l))
# [(3, 4), (2, 3), (3, 3), (5, 6)]
This ought to do the trick:
[x for i, x in enumerate(l) if any(y[::-1] == x for y in l[i:])]
Out[23]: [(3, 4), (2, 3)]
Expanding the initial list a little bit with different orderings:
l =[(3,4),(2,3),(4,3),(3,2), (1,3), (3,1)]
[x for i, x in enumerate(l) if any(y[::-1] == x for y in l[i:])]
Out[25]: [(3, 4), (2, 3), (1, 3)]
And, depending on whether each tuple is guaranteed to have an accompanying "sister" reversed tuple, the logic may change in order to keep "singleton" tuples:
l = [(3, 4), (2, 3), (4, 3), (3, 2), (1, 3), (3, 1), (10, 11), (10, 12)]
[x for i, x in enumerate(l) if any(y[::-1] == x for y in l[i:]) or not any(y[::-1] == x for y in l)]
Out[35]: [(3, 4), (2, 3), (1, 3), (10, 11), (10, 12)]
IMHO, this should be both shorter and clearer than anything posted so far:
my_tuple_list = [(3,4),(2,3),(4,3),(3,2)]
set((left, right) if left < right else (right, left) for left, right in my_tuple_list)
>>> {(2, 3), (3, 4)}
It simply makes a set of all tuples, whose members are exchanged beforehand if first member is > second member.

How to sum up a list of tuples having the same first element?

I have a list of tuples, for example:
(1,3)
(1,2)
(1,7)
(2,4)
(2,10)
(3,8)
I need to be able to sum up the second values based upon what the first value is, getting this result for the example list:
(1,12)
(2,14)
(3,8)
This question is very similar in nature to this one, however, my solution may not use any imports or for loops, and all answers to that question use one or the other. It's supposed to rely on list and set comprehension.
my_set = {x[0] for x in my_tuples}
my_sums = [(i,sum(x[1] for x in my_tuples if x[0] == i)) for i in my_set]
I guess. ... those requirements are not very good for this problem (this solution will be slow ...)
If you can use dictionaries the following should work
x = [(1,3), (1, 2), (1, 7), (2, 4), (2, 10), (3, 8)]
d = {}
[d.__setitem__(first, d.get(first, 0) + second) for first, second in x]
print(list(d.items()))
If you are using python2, you can use map to behave like izip_longest and get the index of where the groups end:
def sums(l):
st = set()
inds = [st.add(a) or ind for ind, (a, b) in enumerate(l) if a not in st]
return [(l[i][0], sum(sub[1] for sub in l[i:j])) for i, j in map(None, inds, inds[1:])]
Output:
In [10]: print(sums(l))
[(1, 12), (2, 14), (3, 8)]
for python 2 or 3 you can just use enumerate and check the index:
def sums(l):
st = set()
inds = [st.add(a) or ind for ind, (a, b) in enumerate(l) if a not in st]
return [(l[j][0], sum(sub[1] for sub in (l[j:inds[i]] if i < len(inds) else l[inds[-1]:])))
for i, j in enumerate(inds, 1)]
same output:
In [12]: print(sums(l))
[(1, 12), (2, 14), (3, 8)]
This is pretty straightforward, but it's definitely O(n**2), so keep your input data small:
data = (
(1,3),
(1,2),
(1,7),
(2,4),
(2,10),
(3,8),
)
d = { k:v for k,v in data }
d2 = [(t1,sum( v for k,v in data if k == t1 )) for t1 in d.keys() ]
print(d2)
Output is
[(1, 12), (2, 14), (3, 8)]
I'd use a defaultdict
from collections import defaultdict
x = [(1,3), (1, 2), (1, 7), (2, 4), (2, 10), (3, 8)]
d = defaultdict(int)
for k, v in x:
d[k] += v
print(list(d.items()))
if you need a one-liner (lambda inline function) using itertools
from itertools import groupby
myfunc = lambda tu : [(k, sum(v2[1] for v2 in v)) for k, v in groupby(tu, lambda x: x[0])])
print(myfunc(x))

modifying something in a "list of lists of tuples" structure without destroying the structure in python

It sounds like a simple question. But, given a:
a = [[(1,2)], [(3,4), (5,6)], [(7,8), (9,10), (11,12)]]
How can I add 1 to each of the first item in the tuples, so that I get the follwing?
b = [[(2,2)], [(4,4), (6,6), [(8,8), (10,10), (12,12)]]
I tried a code as follows:
b = []
for list_of_tuples in a:
for num1, num2 in list_of_tuples:
b.append((num1+1, num2))
b
But, this destroys the original structure. So, How can I get what I want, using two for-loops?
Using a nested list comprehension:
>>> a = [[(1,2)], [(3,4), (5,6)], [(7,8), (9,10), (11,12)]]
>>> b = [[(x+1, y) for x, y in tuples] for tuples in a]
>>> b
[[(2, 2)], [(4, 4), (6, 6)], [(8, 8), (10, 10), (12, 12)]]
As a for with a list comprehension:
b = []
for tuples in a:
b.append([(x+1, y) for x, y in tuples])
Without any list comprehension:
b = []
for tuples in a:
tuples_b = []
for x, y in tuples:
tuples_b.append((x+1, y))
b.append(tuples_b)
using map() and isinstance():
def func(x):
if isinstance(x,list):
return map(func,x)
elif isinstance(x,tuple):
return (x[0]+1,x[1])
a = [[(1,2)], [(3,4), (5,6)], [(7,8), (9,10), (11,12)]]
print map(func,a)
output:
[[(2, 2)], [(4, 4), (6, 6)], [(8, 8), (10, 10), (12, 12)]]
You are almost on right track, but you also need to add the container list for tuples first into b, to recreate original structure
a = [[(1,2)], [(3,4), (5,6)], [(7,8), (9,10), (11,12)]]
b = []
for list_of_tuples in a:
b.append([])
for num1, num2 in list_of_tuples:
b[-1].append((num1+1, num2))
print b
output:
[[(2, 2)], [(4, 4), (6, 6)], [(8, 8), (10, 10), (12, 12)]]
Are you stuck with tuples? It might be better to convert them to lists, since you're clearly modifying them.

Python Easiest Way to Sum List Intersection of List of Tuples

Let's say I have the following two lists of tuples
myList = [(1, 7), (3, 3), (5, 9)]
otherList = [(2, 4), (3, 5), (5, 2), (7, 8)]
returns => [(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]
I would like to design a merge operation that merges these two lists by checking for any intersections on the first element of the tuple, if there are intersections, add the second elements of each tuple in question (merge the two). After the operation I would like to sort based upon the first element.
I am also posting this because I think its a pretty common problem that has an obvious solution, but I feel that there could be very pythonic solutions to this question ;)
Use a dictionary for the result:
result = {}
for k, v in my_list + other_list:
result[k] = result.get(k, 0) + v
If you want a list of tuples, you can get it via result.items(). The resulting list will be in arbitrary order, but of course you can sort it if desired.
(Note that I renamed your lists to conform with Python's style conventions.)
Use defaultdict:
from collections import defaultdict
results_dict = defaultdict(int)
results_dict.update(my_list)
for a, b in other_list:
results_dict[a] += b
results = sorted(results_dict.items())
Note: When sorting sequences, sorted sorts by the first item in the sequence. If the first elements are the same, then it compares the second element. You can give sorted a function to sort by, using the key keyword argument:
results = sorted(results_dict.items(), key=lambda x: x[1]) #sort by the 2nd item
or
results = sorted(results_dict.items(), key=lambda x: abs(x[0])) #sort by absolute value
A method using itertools:
>>> myList = [(1, 7), (3, 3), (5, 9)]
>>> otherList = [(2, 4), (3, 5), (5, 2), (7, 8)]
>>> import itertools
>>> merged = []
>>> for k, g in itertools.groupby(sorted(myList + otherList), lambda e: e[0]):
... merged.append((k, sum(e[1] for e in g)))
...
>>> merged
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]
This first concatenates the two lists together and sorts it. itertools.groupby returns the elements of the merged list, grouped by the first element of the tuple, so it just sums them up and places it into the merged list.
>>> [(k, sum(v for x,v in myList + otherList if k == x)) for k in dict(myList + otherList).keys()]
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]
>>>
tested for both Python2.7 and 3.2
dict(myList + otherList).keys() returns an iterable containing a set of the keys for the joined lists
sum(...) takes 'k' to loop again through the joined list and add up tuple items 'v' where k == x
... but the extra looping adds processing overhead. Using an explicit dictionary as proposed by Sven Marnach avoids it.

Get tuples with max value from each key from a list

I have a list of tuples like this:
[(1, 0), (2, 1), (3, 1), (6, 2), (3, 2), (2, 3)]
I want to keep the tuples which have the max first value of every tuple with the same second value. For example (2, 1) and (3, 1) share the same second (key) value, so I just want to keep the one with the max first value -> (3, 1). In the end I would get this:
[(1, 0), (3, 1), (6, 2), (2, 3)]
I don't mind at all if it is not a one-liner but I was wondering about an efficient way to go about this...
from operator import itemgetter
from itertools import groupby
[max(items) for key, items in groupby(L,key = itemgetter(1))]
It's assuming that you initial list of tuples is sorted by key values.
groupby creates an iterator that yields objects like (0, <itertools._grouper object at 0x01321330>), where the first value is the key value, the second one is another iterator which gives all the tuples with that key.
max(items) just selects the tuple with the maximum value, and since all the second values of the group are the same (and is also the key), it gives the tuple with the maximum first value.
A list comprehension is used to form an output list of tuples based on the output of these functions.
Probably using a dict:
rd = {}
for V,K in my_tuples:
if V > rd.setdefault(K,V):
rd[K] = V
result = [ (V,K) for K,V in rd.items() ]
import itertools
import operator
l = [(1, 0), (2, 1), (3, 1), (6, 2), (3, 2), (2, 3)]
result = list(max(v, key=operator.itemgetter(0)) for k, v in itertools.groupby(l, operator.itemgetter(1)))
You could use a dictionary keyed on the second element of the tuple:
l = [(1, 0), (2, 1), (3, 1), (6, 2), (3, 2), (2, 3)]
d = dict([(t[1], None) for t in l])
for v, k in l:
if d[k] < v:
d[k] = v
l2 = [ (v, k) for (k, v) in d.items() if v != None ]
print l2

Categories

Resources