Mahesh
Mahesh

Reputation: 13

merge two tuples with same key

I have a list that contains two indices for each entry, along with a value. The first two elements in each tuple are the row and column in the table, respectively. The third item is the cell's value.

I want to merge the values of each of the same cells. Here is an example of the data structure:

[
    (1, 2, 'R'),
    (1, 3, 'S'),
    (1, 2, 'S'),
    (2, 3, 'S'),
]

I need to merge the items with matching row/column pairs like this:

[
    (1, 2, 'RS'),
    (1, 3, 'S'),
    (2, 3, 'S'),
]

or:

[
    (1, 2, ('R', 'S')),
    (1, 3, ('S',)),
    (2, 3, ('S',)),
]

Upvotes: 1

Views: 4082

Answers (4)

Mykola Zotko
Mykola Zotko

Reputation: 17854

Another implementation using a dictionary:

dct = {}

for *i, j in lst:
    dct.setdefault(tuple(i), list()).append(j)

[(*k, tuple(v)) for k, v in dct.items()]
# [(1, 2, ('R', 'S')), (1, 3, ('S',)), (2, 3, ('S',))]

Upvotes: 0

Linh
Linh

Reputation: 397

In [1]:     a=[(1, 2, 'R'), (1, 3, 'S'), (1, 2, 'S'), (2, 3, 'S')]
   ...:     b={}
   ...:     for i in a:
   ...:         try:
   ...:             b[i[0:2]] += (i[2],)
   ...:         except(KeyError):
   ...:             b[i[0:2]] = (i[2],)
   ...:     c=[k + (v,) for k, v in b.items()]
   ...:

In [2]: a
Out[2]: [(1, 2, 'R'), (1, 3, 'S'), (1, 2, 'S'), (2, 3, 'S')]

In [3]: b
Out[3]: {(1, 2): ('R', 'S'), (1, 3): ('S',), (2, 3): ('S',)}

In [4]: c
Out[4]: [(1, 2, ('R', 'S')), (1, 3, ('S',)), (2, 3, ('S',))]

Upvotes: 0

martineau
martineau

Reputation: 123491

Here's something that should work. If you're using Python 3, change the.iteritems()method calls to just.items()(which is already an iterator in that version of Python).

from collections import defaultdict

def merge_final_values(values):
    mergeddict = defaultdict(list)
    for group in values:
        mergeddict[group[:-1]].append(group[-1])
    return [(k + (tuple(v),) if len(v) > 1 else k + tuple(v))
                for k, v in mergeddict.iteritems()]

test = [(1, 2, 'R'), (1, 3, 'S'), (1, 2, 'S'), (2, 3, 'S')]

print(merge_final_values(test))

Output:

[(1, 2, ('R', 'S')), (1, 3, 'S'), (2, 3, 'S')]

if you want the merged values concatenated into a single string, just change the return value of the function to:

    return [(k + (''.join(v),)) for k, v in mergeddict.iteritems()]

And you'll get this output instead:

[(1, 2, 'RS'), (1, 3, 'S'), (2, 3, 'S')]

Upvotes: 1

Kasravnd
Kasravnd

Reputation: 107337

You can use itertools.groupby() :

>>> from itertools import groupby
>>> l = [(1, 2, 'R'), (1, 3, 'S'), (1, 2, 'S'), (2, 3, 'S')]
>>> g_list=[list(g) for k, g in groupby(sorted(l),lambda x :x[0:2])]
>>> [(i[0],j[0],k) for i,j,k in [zip(*i) for i in g_list]]
[(1, 2, ('R', 'S')), (1, 3, ('S',)), (2, 3, ('S',))]

in this snippet we first need to sort our list with sorted() function that that sort our tuplse based on those elements , so we have this result :

>>> sorted(l)
[(1, 2, 'R'), (1, 2, 'S'), (1, 3, 'S'), (2, 3, 'S')]

then we grouping the sorted list based on first tow element (lambda x :x[0:2]) so we would have :

>>> g_list
[[(1, 2, 'R'), (1, 2, 'S')], [(1, 3, 'S')], [(2, 3, 'S')]]

So now we have a nested list with same 2 first element , now we need to keep just one of 1th and 2th element and both (or more) 3th elements , in this situation we could use zip() function that will have this results :

>>> [zip(*i) for i in g_list]
[[(1, 1), (2, 2), ('R', 'S')], [(1,), (3,), ('S',)], [(2,), (3,), ('S',)]]

now what we need is chose the 0th element of first and second tuples and whole of 3th elemnt :

(i[0],j[0],k) for i,j,k in ...

Upvotes: 3

Related Questions