Comparing first element of the consecutive lists of tuples in Python
Question: I have a list of tuples, each containing two elements. The first element of
few sublists is common. I want to compare the first element of these sublists
and append the second element in one lists. Here is my list:

    
    
    myList=[(1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(2,8),(3,9),(3,10)]
    

I would like to make a list of lists out of it which looks something like
this:`

    
    
    NewList=[(2,3,4,5),(6,7,8),(9,10)]
    

I hope if there is any efficient way.


Answer: You can use an
[OrderedDict](https://docs.python.org/2/library/collections.html#collections.OrderedDict)
to group the elements by the first subelement of each tuple:

    
    
    myList=[(1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(2,8),(3,9),(3,10)]
    
    from collections import OrderedDict
    
    od  = OrderedDict()
    
    for a,b in myList:
        od.setdefault(a,[]).append(b)
    
    print(list(od.values()))
    [[2, 3, 4, 5], [6, 7, 8], [9, 10]]
    

If you really want tuples:

    
    
    print(list(map(tuple,od.values())))
    [(2, 3, 4, 5), (6, 7, 8), (9, 10)]
    

If you did not care about the order the elements appeared and just wanted the
most efficient way to group you could use a
[collections.defaultdict](https://docs.python.org/2/library/collections.html#collections.defaultdict):

    
    
    from collections import defaultdict
    
    od  = defaultdict(list)
    
    for a,b in myList:
        od[a].append(b)
    
    print(list(od.values()))
    

Lastly, if your data is in order as per your input example i.e sorted you
could simply use
[itertools.groupby](https://docs.python.org/2/library/itertools.html#itertools.groupby)
to group by the first subelement from each tuple and extract the second
element from the grouped tuples:

    
    
    from itertools import groupby
    from operator import itemgetter
    print([tuple(t[1] for t in v) for k,v in groupby(myList,key=itemgetter(0))])
    

Output:

    
    
    [(2, 3, 4, 5), (6, 7, 8), (9, 10)]
    

Again the groupby will only work if your data is _sorted_ by at least the
first element.

Some timings on a reasonable sized list:

    
    
    In [33]: myList = [(randint(1,10000),randint(1,10000)) for _ in range(100000)]
    
    In [34]: myList.sort()
    
    In [35]: timeit ([tuple(t[1] for t in v) for k,v in groupby(myList,key=itemgetter(0))])
    10 loops, best of 3: 44.5 ms per loop
    
    In [36]: %%timeit                                                               od = defaultdict(list)
    for a,b in myList:
        od[a].append(b)
       ....: 
    10 loops, best of 3: 33.8 ms per loop
    
    In [37]: %%timeit
    dictionary = OrderedDict()
    for x, y in myList:
         if x not in dictionary:
            dictionary[x] = [] # new empty list
        dictionary[x].append(y)
       ....: 
    10 loops, best of 3: 63.3 ms per loop
    
    In [38]: %%timeit   
    od = OrderedDict()
    for a,b in myList:
        od.setdefault(a,[]).append(b)
       ....: 
    10 loops, best of 3: 80.3 ms per loop
    

If order matters and the data is _sorted_ , go with the _groupby_ , it will
get even closer to the defaultdict approach if it is necessary to map all the
elements to tuple in the defaultdict.

If the data is not sorted or you don't care about any order, you won't find a
faster way to group than using the _defaultdict_ approach.

