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.
ACCEPTED]
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)])
So this one isn't the best solution but it's a solution. I defined some helper functions that
retrieves last of tuplecompares 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, [])
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]
[[(1, 2, 2), (8, 9, 2), (12, 1, 2)], [(3, 1, 3), (0, 1, 3)]]
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)]]
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