share
Stack Overflowlist all items from list of tuples that share a value
[-4] [3] dyb
[2017-03-09 01:31:07]
[ python ]
[ https://stackoverflow.com/questions/42685049/list-all-items-from-list-of-tuples-that-share-a-value ]

I have a list of tuples:

l = [(x,y,2),(x,y,3),(x,y,4),(x,y,2),(x,y,2),(x,y,3)]

I need to extract tuples that share the last value into a list of lists of tuples:

nl = [[(x,y,2),(x,y,2),(x,y,2)],[(x,y,3),(x,y,3)]]

I don't know the last value of course.

[+3] [2017-03-09 01:55:53] Jonathan Portorreal [ACCEPTED]

with modules

Using groupby from itertools you can group with a lambda by first sorting with that same lambda and then grouping. With a list comprehension you then group together all the groupings and filter out everything that is of length 1 to get rid of tuples that do not share values.

from itertools import groupby

tuples = [(1, 2, 2), (3, 1, 3), (1, 2, 4), (8, 9, 2), (12, 1, 2), (0, 1, 3)]

tuple_tail = lambda (first, mid, last): last

tuples.sort(key=tuple_tail)

print filter(lambda item: len(item) > 1, [list(group) for key, group in groupby(tuples, tuple_tail)])

without modules

So this one isn't the best solution but it's a solution. I defined some helper functions that

  1. retrieves last of tuple
  2. compares equality of two tuples.

Then wrote a custom group function that searches for all elements that are equal by using filter and then map that across all elements to obtain a list with all possible groupings (group all). I couldn't think of a way of using a list comprehension without making a mess so I went with reduce and wrote a function to remove elements that were duplicates and/or length of 1 (fn). This could surely be optimized if you used set or maybe just a different approach in general. Hope this helps you find whatever that approach will be.

tuples = [(1, 2, 2), (3, 1, 3), (1, 2, 4), (8, 9, 2), (12, 1, 2), (0, 1, 3)]
# helper functions
tuple_tail = lambda (first, mid, last): last
is_tuples_equal = lambda tuple1, tuple2: tuple_tail(
    tuple1) == tuple_tail(tuple2)

# groups by last (_,_,last)
group_by_last = lambda tuple: filter(
    lambda item: is_tuples_equal(item, tuple), tuples)

# get all groupings
group_all = map(group_by_last, tuples)

# if group is not in list and not length of 1 insert into list
fn = lambda acc, val: acc if val in acc or len(val) == 1 else acc + [val]

print reduce(fn, group_all, [])

with list comprehension

If you create a dictionary and use the tuple_tail values of each tuple as the key and make the value as the all the tuples that contain that key as their tail. You can then use a list comprehension to accumulate the values of the dictionary and dis include elements of length less than 1.

tuples = [(1, 2, 2), (3, 1, 3), (1, 2, 4), (8, 9, 2), (12, 1, 2), (0, 1, 3)]

mydict = dict()

create = lambda tupl: mydict.update({tuple_tail(tupl): [tupl]})
update = lambda tupl: mydict[tuple_tail(tupl)].append(tupl)
tuple_tail = lambda (first, mid, last): last

populate = lambda tupl: update(tupl) if tuple_tail(tupl) in mydict else create(tupl)
map(populate, tuples)

print [tuple for tuple in mydict.values() if len(tuple) > 1]

end results

[[(1, 2, 2), (8, 9, 2), (12, 1, 2)], [(3, 1, 3), (0, 1, 3)]]

Is it possible to do it without importing any additional module? Preferably as a list comprehension? - dyb
@dyb after some thinking I got it ! Check it out. - Jonathan Portorreal
1
[+1] [2017-03-09 01:47:48] galaxyan

you can use dict to group the item with same last element

x,y= 'x','y'

l = [(x,y,2),(x,y,3),(x,y,4),(x,y,2),(x,y,2),(x,y,3)]
res = {}
for item in l:
  if item[2] not in res:
    res[item[2]] = []
  res[item[2]].append(list(item))

print filter( lambda x: len(x) > 1 , res.values())

[['x', 'y', 2], ['x', 'y', 2], ['x', 'y', 2]], [['x', 'y', 3], ['x', 'y', 3]]

or using pandas

l = pd.Series( [(x,y,2),(x,y,3),(x,y,4),(x,y,2),(x,y,2),(x,y,3) ])

print [ line[1].tolist() for line in l.groupby( lambda x: l[x][2] ) if len(line[1]) > 1]

[[('x', 'y', 2), ('x', 'y', 2), ('x', 'y', 2)], [('x', 'y', 3), ('x', 'y', 3)]]

2
[0] [2017-03-09 01:35:58] smttsp

First, sort according to last elements (You can use this one [1])

Then, group them. You can simply use a for loop. A pseudocode is:

cur_value = list[0][2] #second element of first tuple
llt = []; #list_of_list_of_tuples
for tuple in list:
     l_tpl = []
     if cur_value == tuple[2]:
         l_tpl.append(tuple)
     else:
         if len(l_tpl) > 1:
             llt.append(l_tpl)
if len(l_tpl) > 1:
     llt.append(l_tpl)  # we need to add the last list of tuples. 

I haven't tested and I'm not sure of the syntax.

[1] https://stackoverflow.com/a/3121985/1746852

You should elaborate on how to group them for a complete answer - kingstante
Also OP wants to remove (x,y,4). - Sangbok Lee
@NoticeMeSenpai, sure I've written a pseudo code, thanks for feedback. - smttsp
@SangbokLee That is also included. - smttsp
3