pythongroup-byitertools-groupby

How to print list of objects grouped by itertools' groupby?


I have a class with some fields. I created a list of objects of this class and now I want to group the list by one of the fields inside the objects. It almost works, but unfortunately it shows me only one Dog, but the result for this data should be different.

The code:

from collections import OrderedDict, defaultdict
from itertools import chain
from itertools import groupby

class Animal:
    def __init__(
        self,
        name,
        age,
        description,
        width,
        height
    ):
        self.data = dict(
            name=name,
            age=age,
            description=description,
            width=width,
            height=height
        )
        for k, v in self.data.items():
            setattr(self, k, v)

    def json(self):
        return json.dumps(self.data)
        
        
animals = [Animal('Dog', '3', 'nice dog', 12, 13), Animal('Cat', '2', 'kitty', 12, 23), Animal('Dog', '5', 'woof', 12, 13)]

# print(vulns)

sorted_animals = sorted(animals, key=lambda Animal: Animal.name)
grouped_animals = [list(result) for key, result in groupby(
    sorted_animals, key=lambda Animal: Animal.name)]
    
report = {"data": OrderedDict(), "meta": {"animals": {}}}

# print(grouped)
for group in grouped_animals:
    for animal in group:
        report["meta"]["animals"][animal.name] = animal.name, animal.age, animal.width
print(report)

The result:

{'data': OrderedDict(), 'meta': {'animals': {'Cat': ('Cat', '2', 12), 'Dog': ('Dog', '5', 12)}}}

What I want:

{'data': OrderedDict(), 'meta': {'animals': {'Cat': ('Cat', '2', 12), 'Dog': ('Dog', '5', 12), 'Dog': ('Dog', '3', 12)}}}

So I'm missing the first animal (('Dog', '3', 'nice dog', 12, 13)) in my list. How to solve this?


Solution

  • You can use the following code as alternative:

    report = {"data": OrderedDict(), "meta": {"animals": defaultdict(list)}}
    
    for group in grouped_animals:
        for animal in group:
            report["meta"]["animals"][animal.name].append((animal.name, animal.age, animal.width))
    

    Output:

    >>> report
    {'data': OrderedDict(),
     'meta': {'animals': defaultdict(list,
                  {'Cat': [('Cat', '2', 12)],
                   'Dog': [('Dog', '3', 12), ('Dog', '5', 12)]})}}