Tatu Bogdan
Tatu Bogdan

Reputation: 596

Python 3 list comprehension sum and concatenation

mylist =[[16, 'August', 2014, 540, 10], [16, 'Iunie', 2014, 100, 20], [23,'August', 2014, 540,10], [23,'Septembrie', 2016, 540,30], [21,'August', 2014, 422, 30]]

What I want to achieve is this:

manipulate = [[16, 'August 2014, Iunie 2014', 540, 30], [23, 'August 2014, Septembrie 2016', 540, 40], [21, 'August', 2014, 422, 30]]

And to explain it, in mylist (list of lists) I want to check each list for the index 0 (first element) when it founds the same value element (in my example 16 ===16) and do the fallowing operation: keep only the first list and accumulate to it index 1 + index 2 (like this example -> 'August', 2014 and 'Iunie', 2014 to 'August 2014, Iunie 2014') and sum the index 4 (like in my example 20 + 10).

I manage to do this:

manipulate=[i for i in mylist if i[0] not in [mylist[idx][0] for idx in range(0,mylist.index(i))]]

but this will output:

[[16, 'August', 2014, 540, 10], [23, 'August', 2014, 540, 10], [21, 'August', 2014, 422, 30]]

What I have to add in order to also do my desired computations?, I work with python 3. Thank you so much!

Upvotes: 1

Views: 211

Answers (3)

Ma0
Ma0

Reputation: 15204

This is quite verbose but I feel like it had to be, to be understandable\readable:

mylist = [[16, 'August', 2014, 540, 10], [16, 'Iunie', 2014, 100, 20], [23, 'August', 2014, 540, 10], [23, 'Septembrie', 2016, 540, 30], [21, 'August', 2014, 422, 30]]

g = {}
for x, *y in mylist:
    g.setdefault(x, []).append(y)

def formater(obj, a_list):
    if len(a_list) == 1:
        return [obj] + a_list[0]
    else:
        conc = ', '.join('{} {}'.format(sub[0], sub[1]) for sub in a_list)
        return [obj, conc, a_list[0][2], sum(sub[3] for sub in a_list)]

manipulate = [formater(k, v) for k, v in g.items()]
print(manipulate)  # [[16, 'August 2014, Iunie 2014', 540, 30], [21, 'August', 2014, 422, 30], [23, 'August 2014, Septembrie 2016', 540, 40]]

Upvotes: 1

Ajax1234
Ajax1234

Reputation: 71461

You can try this:

mylist =[[16, 'August', 2014, 540, 10], [16, 'Iunie', 2014, 100, 20], [23,'August', 2014, 540,10], [23,'Septembrie', 2016, 540,30], [21,'August', 2014, 422, 30]]

new_list = [[mylist[i][0]]+[mylist[i][1]+" "+str(mylist[i][2])]+mylist[i][3:] for i in range(len(mylist))]

final_lists = [[c+", "+d if isinstance(c, str) and isinstance(d, str)  else c+d if c != d else c for c, d in zip(new_list[i], new_list[i+1])] for i in range(0, len(new_list)-1, 2)]+mylist[-1]

Upvotes: 1

tobias_k
tobias_k

Reputation: 82929

Assuming that the list is already sorted by the first elements, you can use itertools.groupby to group the elements and then assemble the new sublists.

manipulate = []
for group in (list(g) for k, g in itertools.groupby(mylist, key=lambda x: x[0])):
    lst = [group[0][0]] + [x for g in group for x in g[1:3]] + [group[0][3]] + [sum(g[-1] for g in group)]
    manipulate.append(lst)

You could even put those in a single horrible list comprehension if you want...

manipulate = [[group[0][0]] + [x for g in group for x in g[1:3]] + [group[0][3]] + [sum(g[-1] for g in group)]
              for group in (list(g) for k, g in itertools.groupby(mylist, key=lambda x: x[0]))]

The result is this (I do not merge the strings, as I'm not sure you really meant this):

[[16, 'August', 2014, 'Iunie', 2014, 540, 30], 
 [23, 'August', 2014, 'Septembrie', 2016, 540, 40], 
 [21, 'August', 2014, 422, 30]]

If you want to merge the dates, use this slightly more horrible list comprehension:

manipulate = [[group[0][0]] + [', '.join(' '.join(map(str, g[1:3])) for g in group)] + [group[0][3]] + [sum(g[-1] for g in group)]
              for group in (list(g) for k, g in itertools.groupby(mylist, key=lambda x: x[0]))]

This way, the result is:

[[16, 'August 2014, Iunie 2014', 540, 30], 
 [23, 'August 2014, Septembrie 2016', 540, 40], 
 [21, 'August 2014', 422, 30]]

This works with an arbitrary number of elements per group. If the sublists are not sorted by first element, either sort them first, or use a dictionary to do the grouping.

Upvotes: 1

Related Questions