1

I have some issues to read a nested data structure from .json file via list comprehension.

This is my file:

"persons": [
    {
      "A": [
        {
          "type": "type1",
          "value": "",
          "is_valid": true
        },
        {
          "type": "type1",
          "value": "",
          "is_valid": true
        }
      ]
    },
    {
      "B": [
        {
          "type": "type2",
          "value": "",
          "is_valid": true
        }
      ]
    },
    {
      "C": [
        {
          "type": "type3",
          "value": "",
          "is_valid": true
        },
        {
          "type": "type3",
          "value": "",
          "is_valid": false
        }
      ]
    }
  ]

I want to read all the "persons" fields and return a list of Person objects.

Currently this is my approach:

def get_all() -> list[Person]:
    persons = []
    for p in config['persons']:
        for key, values in p.items():
            for value in values:
                persons.append(Person(type=value['type'], name=f'{key}', value='{}'.format(value['value']), is_valid=value['is_valid']))
    return persons

I tried to convert it to a list comprehesion:

return [[(k, v) for k, v in d.items()] for d in config['persons']]

But it returns a list of lists.

My Person object has 4 fields:

name: str
type: str
value: str
is_valid: bool
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Ran Pol
  • 85
  • 7
  • 2
    What exact error or undesired behavior do you get with hte new code? – mousetail Feb 09 '23 at 10:22
  • Also why do you even want to use a list comprehension? It's not in any way better or more readable – mousetail Feb 09 '23 at 10:23
  • Whats wrong with your `get_all` function? looks fine for me – Tom McLean Feb 09 '23 at 10:26
  • `[[ ... ] for ... in ...]` that's a nested list. Why did you write that if you don't want it? If you want a list of `Person` objects, why did you not write `[Person(...) for ... in ...]`? – mkrieger1 Feb 09 '23 at 10:26
  • "I tried to convert it to a list comprehension... But it returns a list of lists." - yes, a list of lists of `(k, v)` pairs. This is because a) you have used a nested list comprehension; b) the innermost part is skipping the code that would get from the `(k, v)` data to the corresponding `Person` (i.e. the logic to iterate over `v` and instantiate the class). The second part is trivial, and can be considered a typo (you're just missing the next "level" of list comprehension). To get a flattened result (instead of a list of lists of lists of `Person`s), see the linked duplicates. – Karl Knechtel Feb 09 '23 at 11:29

3 Answers3

2

To proceed with list comprehension use the following approach:

persons = [Person(name=k, **f)
           for d in config['persons'] for k, v in d.items() for f in v]

Note how field (dict) is unpacked **f (to fit the remaining object properties)

RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
1

Try:

>>> [Person(type=value['type'], name=f'{key}', value='{}'.format(value['value']), is_valid=value['is_valid'])
         for p in config['persons']
         for key, values in p.items()
         for value in values]

[Person(type='type1', name='A', value='', is_valid=True),
 Person(type='type1', name='A', value='', is_valid=True),
 Person(type='type2', name='B', value='', is_valid=True),
 Person(type='type3', name='C', value='', is_valid=True),
 Person(type='type3', name='C', value='', is_valid=False)]
Corralien
  • 109,409
  • 8
  • 28
  • 52
0

In the below illustration persons object is of type list containing config['persons']

return [
    (person.keys()[0], type_obj)
    for person in persons
    for type_obj in person.values()[0]
]
dinolin
  • 78
  • 9