How to group lists with common elements into dict using functional approach in python?

Question:

I am trying to aggregate lists into dict. First column can be treated as id and second column as some random element. I want all elements assigned to the same id to be grouped in a list under that id. Id=None, empty lists need to be filtered out and not allow duplicate elements.

Probably seeing input and output will be more expressive
This is input:

[
    [1, 1],
    [2, 1],
    [2, 2],
    [2, 3],
    [2, 3],
    [2, 4],
    [],
    [None, 5]
]

This is expected output:

{
    1: [1],
    2: [1, 2, 3, 4]
}

I got stuck at this functional and imperative hybrid:

filtered_groups = list(filter(lambda group: len(group) == 2 and group[0] is not None, groups))
grouper = {}
for group in filtered_groups:
    id = group[0]
    element = group[1]
    grouper_entry = grouper.get(id)
    if not grouper_entry:
        grouper_entry = grouper[id] = []
    if element not in grouper_entry:
        grouper_entry.append(element)

expected_result = {
    1: [1],
    2: [1, 2, 3, 4]
}
assert grouper == expected_result

How can I rewrite this for loop into mapping/reducing/grouping function to achieve expected result?

Asked By: hdw3

||

Answers:

Try:

lst = [[1, 1], [2, 1], [2, 2], [2, 3], [2, 3], [2, 4], [], [None, 5]]

out, seen = {}, set()
for a, b in (item for item in lst if len(item) == 2 and item[0] is not None):
    if (a, b) not in seen:
        out.setdefault(a, []).append(b)
        seen.add((a, b))

print(out)

Prints:

{1: [1], 2: [1, 2, 3, 4]}
Answered By: Andrej Kesely

A solution using defaultdict

from collections import defaultdict

lst = [[1, 1], [2, 1], [2, 2], [2, 3], [2, 3], [2, 4], [], [None, 5]]

dic = defaultdict(list)

for sublist in lst:
    if (len(sublist) == 2):
        if sublist[0] != None:
            id, val = sublist
            dic[id].append(val)

print(dic)
Answered By: elka