Search code examples
pythondictionary-comprehension

Python dictionary initialization and values append to list


Question: Write function that for a given list of objects, returns a dictionary of type: [object]. For example: func([1,2.0,3,'g']) returns: {'i':[1,3], 'f': [2.0], 'c': ['g'], 'o': []}

  • key i for ints
  • key f for floats
  • key c for chars
  • key o for others

My code:

def make_dict(lst):
    my_dict = {'i': [], 'f': [], 'c': [], 'o': []}
    [my_dict['i'].append(item) if isinstance(item, int) else my_dict['f'].append(item) if isinstance(
        item, float) else my_dict['c'].append(item) if isinstance(item, str) and len(item) == 1 else my_dict['o'].append(item) for item in lst]
    return my_dict

This function returning the corrent dictionary, but I need to make it a One-Liner, plus, I don't like the way it's done. I know the use of list comprehension is bad here.

My though process was to first make this a multiple lines function, which i did using for loops and if elif statements, Then i tried to combine those lines and eventually got it down to 3.

This is the for loop i used before combining it into a list comprehenson:

for item in lst:
    if isinstance(item, int):
        my_dict['i'].append(item)
    elif isinstance(item, float):
        my_dict['f'].append(item)
    elif isinstance(item, str) and len(item) == 1:
        my_dict['c'].append(item)
    else:
        my_dict['o'].append(item)
return my_dict

My problem: I know i need to use some sort of Dictionary comprehension combined with map() of filter() in some way, but after searching the internet and finding noting.. I just don't know how to do it.

Maybe you can help me? THANKS!


Solution

  • What you want is to group the data by the first letter of their type so

    • get the first letter of their type type(x).__name__[0]
    • group the data by this criteria

    You need to provide data to groupby sorted by the same criteria you'll use for the grouping. the {k:list(v) part is to move from a groupby object to a dict

    from itertools import groupby
    
    def make_dict(lst):
        sorter = lambda x:type(x).__name__[0] if type(x).__name__ in ('int', 'float', 'str') else 'o'
        return {k:list(v) for k,v in groupby(sorted(lst, key=sorter), key=sorter)}
    
    r = make_dict([1,2.0,3,'g']) # {'f': [2.0], 'i': [1, 3], 's': ['g']}
    print(r)
    

    Using filter, but not efficient as you iterate the list multiple times

    def make_dict(lst):
        return {'i': list(filter(lambda x: isinstance(item, int), lst)), 
                'f': list(filter(lambda x: isinstance(item, float), lst)), 
                's': list(filter(lambda x: isinstance(item, str), lst)), 
                'o': type(x).__name__ not in ('int', 'float', 'str')}