Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sum multiple lists-of-lists on certain sub-list's fields?

I have 3 lists-of-lists.

The sub-lists' field 1 is a name, field 2 is a number, and field 3 is a number. This format is always the same, and doesn't change. There are always the same names in the 3 lists; however, the order may not be the same.

a = [['jane', '1', '120'], ['bob', '3', '35'], ['joe', '5', '70']]
b = [['bob', '1', '12'], ['jane', '2', '240'], ['joe', '1', '100']]
c = [['joe', '2', '30'], ['jane', '5', '45'], ['bob', '0', '0']]

I would like a result (any object type) with the sum of fields 2 & 3 of the lists' sub-lists.

result = [['jane', '8', '405'], ['bob', '4', '47'], ['joe', '8', '200']]

In pseudo Python3 code, I'm guessing it'd look like this, but I cannot figure out the correct way to do it in Python3. Let alone doing it in a Pythonic way:

def sum_f2_f3(list_a, list_b)
    where element[0] in list_a.sub_list == element[0] in list_b.sub_list:
        x = element[0]
        result[x:1] = list_a.sub_list[0:1] + list_b.sub_list[0:1]
        result[x:2] = list_a.sub_list[0:2] + list_b.sub_list[0:2]
    return result

result = sum_f2_f3(sum_f2_f3(a,b), c)

Any ideas? What built-in Python tools can help me with this?

like image 272
svenglar Avatar asked Dec 15 '22 09:12

svenglar


1 Answers

To illustrate why using the right data structures makes things a lot easier…

Let's say that a, b, and c were actually dicts, and your numbers were actually ints instead of strs. After all, the whole point of a dict is to look things up by name, and the whole point of an int is to be able to do arithmetic. So:

a = {'jane': [1, 120], 'bob': [3, 35], 'joe': [5, 70]}
b = {'bob': [1, 12], 'jane': [2, 240], 'joe': [1, 100]}
c = {'joe': [2, 30], 'jane': [5, 45], 'bob': [0, 0]}

Now, all you have to do is this:

result = {}
for d in a, b, c:
    for k, v in d.items():
        if not k in result:
            result[k] = [0, 0]
        result[k][0] += v[0]
        result[k][1] += v[1]

And the result is:

{'bob': [4, 47], 'jane': [8, 405], 'joe': [8, 200]}

There's still a bit of room for improvement—you can use a defaultdict to get rid of the if not k in result: bit—but even with just novice-level stuff this is pretty compact and simple.


But what if you got those lists as input—you'd like to have nice dicts in the end, but you don't start there?

You can write a function to convert them, like this:

def convert(list_of_lists):
    result = {}
    for element in list_of_lists:
        key = element[0]
        values = []
        for value in element[1:]:
            values.append(int(value))
        result[key] = values
    return result

And if you spot the familiar values = []… for value in … values.append(…) pattern, you can turn that into the simple list comprehension [int(value) for value in element[1:]]. And then the whole thing is the dict equivalent of the same pattern, so you can reduce all of it to:

return {element[0]: [int(value) for value in element[1:]] for element in list_of_lists}

Meanwhile, if you need to convert back to the original form, that's just:

def unconvert(dict_of_lists):
    result = []
    for key, values in dict_of_lists.items():
        element = [key] + [str(value) for value in values]
        result.append(element)
    return result
like image 142
abarnert Avatar answered May 19 '23 13:05

abarnert