Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse json to get all values of a specific key within an array?

I'm having trouble trying to get a list of values from a specific key inside an json array using python. Using the JSON example below, I am trying to create a list which consists only the values of the name key. Original JSON:

[
    {
        "id": 1,
        "name": "Bulbasaur",
        "type": [
            "grass",
            "poison"
        ]
    },
    {
        "id": 2,
        "name": "Ivysaur",
        "type": [
            "grass",
            "poison"
        ]
    }
]

Expected:

["Bulbasaur", "Ivysaur"]

Below is the code of my approach:

import json
try:
    with open("./simple.json", 'r') as f:
        contents = json.load(f)
except Exception as e:
    print(e)

print(contents[:]["name"])

I'm trying to go to an approach where i don't need to loop every single index and append them, something like the code above. Is this approach possible using python' json library?

like image 777
Radhian Amri Avatar asked May 16 '19 07:05

Radhian Amri


3 Answers

You cannot do contents[:]["name"] since contents is a list is a dictionary with integer indexes, and you cannot access an element from it using a string name.

To fix that, you would want to iterate over the list and get the value for key name for each item

import json
contents = []

try:
    with open("./simple.json", 'r') as f:
        contents = json.load(f)
except Exception as e:
    print(e)


li = [item.get('name') for item in contents]
print(li)

The output will be

['Bulbasaur', 'Ivysaur']
like image 135
Devesh Kumar Singh Avatar answered Sep 18 '22 02:09

Devesh Kumar Singh


This is not a real answer to the question. The real answer is to use a list comprehension. However, you can make a class that allows you to use specifically the syntax you tried in the question. The general idea is to subclass list so that a slice like [:] returns a special view (another class) into the list. This special view will then allow retrieval and assignment from all the dictionaries simultaneously.

class DictView:
    """
    A special class for getting and setting multiple dictionaries
    simultaneously. This class is not meant to be instantiated
    in its own, but rather in response to a slice operation on UniformDictList.
    """
    def __init__(parent, slice):
        self.parent = parent
        self.range = range(*slice.indices(len(parent)))

    def keys(self):
        """
        Retreives a set of all the keys that are shared across all
        indexed dictionaries. This method makes `DictView` appear as
        a genuine mapping type to `dict`.
        """
        key_set = set()
        for k in self.range:
            key_set &= self.parent.keys()
        return key_set

    def __getitem__(self, key):
        """
        Retreives a list of values corresponding to all the indexed
        values for `key` in the parent. Any missing key will raise
        a `KeyError`.
        """
        return [self.parent[k][key] for k in self.range]

    def get(self, key, default=None):
        """
        Retreives a list of values corresponding to all the indexed
        values for `key` in the parent. Any missing key will return
        `default`.
        """
        return [self.parent[k].get(key, default) for k in self.range]

    def __setitem__(self, key, value):
        """
        Set all the values in the indexed dictionaries for `key` to `value`.
        """
        for k in self.range:
            self.parent[k][key] = value

    def update(self, *args, **kwargs):
        """
        Update all the indexed dictionaries in the parent with the specified
        values. Arguments are the same as to `dict.update`.
        """
        for k in self.range:
             self.parent[k].update(*args, **kwargs)


class UniformDictList(list):
    def __getitem__(self, key):
        if isinstance(key, slice):
            return DictView(self, key)
        return super().__getitem__(key)

Your original code would now work out of the box with just one additional wrap in UniformDictList:

import json
try:
    with open("./simple.json", 'r') as f:
        contents = UniformDictList(json.load(f))
except Exception as e:
    print(e)

print(contents[:]["name"])
like image 36
Mad Physicist Avatar answered Sep 18 '22 02:09

Mad Physicist


Try this with list comprehensions:

print([d["name"] for d in contents])
like image 28
olinox14 Avatar answered Sep 20 '22 02:09

olinox14