How to merge the elements of nested list with changing inside elements?

Question:

I have a nested list. Two of inside elements can be a same, one is different. I need to change that list in some way that better to demonstrate.

before = [['a','a', 1],['a','a', 2], ['a','b', 6], ['a','b', 0], ['a','c',5]
#after some changes
after = [['a','a', 3], ['a','b', 6], ['a','c',5]]

So i need to summarize the "i[2] elements for i in before" if i[0],i[1] are same. That formulation is already looking like comprehension, but i see no ways to do it in this way.

I did it like that. But i sure it’s not most elegant solution.

before = [['a','a', 1],['a','a', 2], ['a','b', 6], ['a','b', 0], ['a','c',5]]
#creating a list of unique combinations, actually it's already created and used for another aims too
after = set([(i[0],i[1],0) for i in before])
after = [list(i) for i in after]
# output is [['a', 'c', 0], ['a', 'b', 0], ['a', 'a', 0]]

for k,i in enumerate(after):
    #starting the loop from list of uniq_combinations
    q = 0 #for element we need to summarize, reseting var for each iteration
    for j in before:
            if (i[0],i[1]) == (j[0],j[1]):
                q = j[2] #the third element for each nested list
                after[k][2] +=q #summarizing the result while looking for same combination
print(after)
#output have correct result [['a', 'a', 3], ['a', 'b', 6], ['a', 'c', 5]]

I’ve looked in itertools lib, but can’t find suitable method

Asked By: Sharmat

||

Answers:

You can use itertools.groupby, as long as elements with the same key are always adjacent.

from itertools import groupby
l = [['a','a', 1],['a','a', 2], ['a','b', 6], ['a','b', 0], ['a','c',5]]
res = [[*k, sum(o[2] for o in g)] for k, g in groupby(l, lambda o:o[:2])]

A defaultdict can also be used to store the sum for each key.

from collections import defaultdict
d = defaultdict(int)
for *k, v in l: d[tuple(k)] += v
res = [[*k, v] for k, v in d.items()]
Answered By: Unmitigated

Just keep track of the current count for each pair of characters in a dictionary. As you iterate over the items in the before list, retrieve the value at item[0:2] in the dictionary, and add item[2] to this value.

result = {}
for item in before:
    # Convert item[0:2] to tuple because dict keys need to be immutable
    key = tuple(item[0:2]) 

    # Get value in result at key (or zero if it doesn't exist)
    # Then add item[2] to it
    # Then assign it back to result[key]
    result[key] = result.get(key, 0) + item[2]

This gives result as:

{('a', 'a'): 3, ('a', 'b'): 6, ('a', 'c'): 5}

Now, simply iterate over the keys and values of result and create your after list:

after = [[*key, val] for key, val in result.items()]

which gives:

[['a', 'a', 3], ['a', 'b', 6], ['a', 'c', 5]]
Answered By: Pranav Hosangadi

Almost the same approach that Pranav Hosangadi uses.

We iterate the list and make a dictionary whose keys are the first two elements as a tuple and the value is the sum of the third coordinate.
We don’t have to make the addition manually: collections.Counter can do it for us:

from collections import Counter

before_counter = Counter()
for triad in before:
    # Tuple as a key, third element as the quantity
    before_counter.update({(triad[0], triad[1]) : triad[2]})

Then just convert it into the desired list:

after = [[*pair, count] for pair, count in before_counter.items()]
Answered By: Jorge Luis
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.