Sabba
Sabba

Reputation: 561

Merge List of lists where sublists have common elements

I have a list of lists like this

list = [[1, 2], [1, 3], [4, 5]]

and as you see the first element of the first two sublists is repeated

So I want my output too be:

list = [[1, 2, 3], [4, 5]]

Thank you

Upvotes: 3

Views: 3839

Answers (4)

Wolph
Wolph

Reputation: 80011

Although arguably unreadable:

# Note the _ after the list, otherwise you are redefining the list type in your scope
list_ = [[1, 2], [1, 3], [4, 5]]

from itertools import groupby
grouper = lambda l: [[k] + sum((v[1::] for v in vs), []) for k, vs in groupby(l, lambda x: x[0])]

print grouper(list_)

A more readable variant:

from collections import defaultdict
groups = defaultdict(list)
for vs in list_:
    group[vs[0]] += vs[1:]

print group.items()

Note that these solve a more generic form of your problem, instead of [[1, 2], [1, 3], [4, 5]] you could also have something like this: [[1, 2, 3], [1, 4, 5], [2, 4, 5, 6], [3]]


Explanation about the _. This is why you don't want to overwrite list:

spam = list()
print spam
# returns []

list = spam
print list
# returns []

spam = list()
# TypeError: 'list' object is not callable

As you can see above, by setting list = spam we broke the default behaviour of list().

Upvotes: 0

Alex
Alex

Reputation: 731

You can use python sets, because you can compute intersection and union pretty easy. The code would be more clear, but the complexity would probably be comparable to the other solutions.

Upvotes: 0

halex
halex

Reputation: 16393

The following code should solve your problem:

def merge_subs(lst_of_lsts):
    res = []
    for row in lst_of_lsts:
        for i, resrow in enumerate(res):
            if row[0]==resrow[0]:
                res[i] += row[1:]
                break
        else:
            res.append(row)
    return res

Note that the elsebelongs to the inner for and is executed if the loop is exited without hitting the break.

Upvotes: 1

Emmanuel
Emmanuel

Reputation: 14209

I have a solution that builds a dict first with the 1st values, then creates a list from that, but the order may not be the same (i.e. [4, 5] may be before [1, 2, 3]):

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> map(lambda x: d[x[0]].append(x[1]), l)
[None, None, None]
>>> d
defaultdict(<type 'list'>, {1: [2, 3], 4: [5]})
>>> [[key] + list(val) for key, val in d.iteritems()]
[[1, 2, 3], [4, 5]]

Upvotes: 1

Related Questions