Search code examples
pythonloopsnestedlist-comprehensiondictionary-comprehension

python lists - convert an existing list of lists into a dict with multiple values per key using a comprehension


I have a relatively simple problem that is easily solved with setdefault, but I'm self-learning comprehensions right now and can't figure out how to do this with a comprehension.

Let's say I have a nested list where some of the inner lists have the same keys. This means that I should be able to generate a dict where some keys have multiple values. I keep trying to somehow append the values but every time it just returns that last single digit value or else give an error.

Here is an example:

>>> strlist
['hello w', 'hello', 'hello c', 'hello c c', 'dog']

>>> [[k,v] for k in set(sum([x.split() for x in strlist],[])) for v,x in enumerate(strlist) if k in x]
[['hello', 0], ['hello', 1], ['hello', 2], ['hello', 3], ['w', 0], ['c', 2], ['c', 3], ['dog', 4]]

I also tried it with a list of tuples, a tuple of tuples, a set of lists, a set of tuples, etc. Still can't get it to work with a comprehension.

Here are a few failed attempts:

>>> dict([(k,v) for k in set(sum([x.split() for x in strlist],[])) for v,x in enumerate(strlist) if k in x])
{'hello': 3, 'w': 0, 'c': 3, 'dog': 4}

>>> {k:k[v] for k,v in [[k,v] for k in set(sum([x.split() for x in strlist],[])) for v,x in enumerate(strlist) if k in x]}
Traceback (most recent call last):
  File "<pyshell#285>", line 1, in <module>
    {k:k[v] for k,v in [[k,v] for k in set(sum([x.split() for x in strlist],[])) for v,x in enumerate(strlist) if k in x]}
  File "<pyshell#285>", line 1, in <dictcomp>
    {k:k[v] for k,v in [[k,v] for k in set(sum([x.split() for x in strlist],[])) for v,x in enumerate(strlist) if k in x]}
IndexError: string index out of range

>>> {k:{v} for k,v in [[k,v] for k in set(sum([x.split() for x in strlist],[])) for v,x in enumerate(strlist) if k in x]}
{'hello': {3}, 'w': {0}, 'c': {3}, 'dog': {4}}

The goal is to get this:

>>> {'hello': {0, 1, 2, 3], 'w': {0}, 'c': {2, 3}, 'dog': {4}}

Is this even possible with a comprehension or must I use one of the more common traditional loop methods?


Solution

  • Use your method to transform strlist to list of lists and then you can use collections.defaultdict:

    from collections import defaultdict
    
    lst = [
        ["hello", 0],
        ["hello", 1],
        ["hello", 2],
        ["hello", 3],
        ["w", 0],
        ["c", 2],
        ["c", 3],
        ["dog", 4],
    ]   
    
    d = defaultdict(set)
    for x, y in lst:
        d[x].add(y)
        
    print(d)
    # defaultdict(<class 'set'>, {'hello': {0, 1, 2, 3}, 'w': {0}, 'c': {2, 3}, 'dog': {4}})
    

    Since, you ask for a dictionary-comprehension:

    d = {k: set(y for x, y in lst if x == k) for k, _ in lst}