Search code examples
pythondictionarydefaultdict

Python defaultdict - add another key?


I'm probably not using the right words here, but basically I want to add another key next to the first key that's provided.

This is what I currently have:

def transform_result(self, data):
    type_map = defaultdict(list)
    for entry in data:
        type_map[entry['type']].append({
            'id': entry['id'],
            'tag': entry['tag'],
        })
    ret = []
    for key, value, in type_map.items():
        ret.append({
            'type': key,
            'tags': value,
        })
    return ret

Input:

[
    OrderedDict([
        ('id', 1),
        ('type', 'Color'),
        ('writable', True),
        ('tag', 'Blue')
    ]),
    OrderedDict([
        ('id', 2),
        ('type', 'Color'),
        ('writable', True),
        ('tag', 'Red')
    ]),
    OrderedDict([
        ('id', 3),
        ('type', 'Color'),
        ('writable', True),
        ('tag', 'Green')
    ]),
    OrderedDict([
        ('id', 4),
        ('type', 'Shape'),
        ('writable', False),
        ('tag', 'Square')
    ]),
    OrderedDict([
        ('id', 5),
        ('type', 'Shape'),
        ('writable', False),
        ('tag', 'Circle')
    ])
]

Desired output:

[
    {
        'type': 'Color',
        'writable': True,
        'tags': [
            {
                'tag': 'Blue',
                'id': 1
            },
            {
                'tag': 'Red',
                'id': 2
            },
            {
                'tag': 'Green',
                'id': 3
            }
        ]
    },
    {
        'type': 'Shape',
        'writable': False,
        'tags': [
            {
                'tag': 'Square',
                'id': 4
            },
            {
                'tag': 'Circle',
                'id': 5
            },

        ]
    },
]

How should this be accomplished?


Edit: I got it, sorry I totally rubber ducked this. Here's my hacky solution:

def transform_result(self, data):
    type_map = defaultdict(list)
    for entry in data:
        type_map[entry['type'], entry['many']].append({
            'id': entry['id'],
            'tag': entry['tag'],
        })
    ret = []
    for key, value, in type_map.items():
        ret.append({
            'type': key[0],
            'many': key[1],
            'tags': value
        })
    return ret

Basically, the thing that was confusing me was how to access the many after the first loop had completed. My solution was to quickly put the type and many together in a little list, then access them with [0] and [1], it works!


Solution

  • I can't say that I like your data model, but for your given input and desired output, you almost had it:

    def transform_result(self, data):
        type_map = defaultdict(list)
        for entry in data:
            type_map[entry['type'], entry['writable']].append({
                'id': entry['id'],
                'tag': entry['tag'],
            })
        ret = []
        for (k_type, k_writable), value in type_map.items():
            ret.append({
                'type': k_type,
                'writable': k_writable,
                'tags': value,
            })
        return ret