Search value in a list of lists and dictionaries

Viewed 101

I'm trying to write a code that checks if a specific value in a list that contains dictionaries and/or lists is present, and it returns True or False.

Note: I cannot change the structure of the data.

I manage to have this function that does the job for the current data type that I have:

def search_value_list_dic(value, list_dic):

    if any(isinstance(el, list) for el in list_dic):
        number_lists = len(list_dic)
        list_or = []
        for i in range(number_lists):            
            if value in list_dic[i]:  
                list_or.append('true')
            else:
                  list_or.append('false')
    
        if 'true' in list_or: return True
        else: return False
    
    
    if value in list_dic:
         return True
    if value not in list_dic:
         return False

I'm aware that this is not the most efficient way of doing it. Does anyone have any ideas on how to improve?

I also would like to make it more generic, basically to search for every item on the list (even if it has list on list on list and so on).

Example of data structure:


[{'id': 'BuMnLoadRequestCfgBufferRequestOnHysteresis', 'view_id': 122, 'label': {'key': 'BUMN_LOAD_REQUEST_CFGBUFFERREQUESTONHYSTERESIS', 'en': 'Hysteresis to start buffer cylinder loading', 'de': 'Einschalthysterese Puffer'}, 'range': None, 'testing_conditions': [[{'ordName': 'BuMnLoadRequestMnIsActive', 'ordValue': '1', 'type': 'single', 'condition': 'BuMn.load.request.mnIsActive.1 == true', 'condition_testing': 'BuMn.load.request.mnIsActive.1 == 1'}, 'OR', {'ordName': 'BuMnLoadHydMnIsFlowControlActive', 'ordValue': '1', 'type': 'single', 'condition': 'BuMn.load.hyd.mnIsFlowControlActive.1 == true', 'condition_testing': 'BuMn.load.hyd.mnIsFlowControlActive.1 == 1'}], {'ordName': 'BuMnLoadRequestInAHSHydraulic', 'ordValue': '1', 'type': 'single', 'condition': 'BuMn.load.request.inAHSHydraulic.4 == BUFFER', 'condition_testing': 'BuMn.load.request.inAHSHydraulic.4 == 1'}], 'type': 'customkeypadonly_text_linear', 'user_level': 3}, {'id': 'BuMnLoadRequestCfgBufferRequestOffHysteresis', 'view_id': 122, 'label': {'key': 'BUMN_LOAD_REQUEST_CFGBUFFERREQUESTOFFHYSTERESIS', 'en': 'Hysteresis to stop buffer cylinder loading', 'de': 'Ausschalthysterese Puffer'}, 'range': None, 'testing_conditions': [[{'ordName': 'BuMnLoadRequestMnIsActive', 'ordValue': '1', 'type': 'single', 'condition': 'BuMn.load.request.mnIsActive.1 == true', 'condition_testing': 'BuMn.load.request.mnIsActive.1 == 1'}, 'OR', {'ordName': 'BuMnLoadHydMnIsFlowControlActive', 'ordValue': '1', 'type': 'single', 'condition': 'BuMn.load.hyd.mnIsFlowControlActive.1 == true', 'condition_testing': 'BuMn.load.hyd.mnIsFlowControlActive.1 == 1'}], {'ordName': 'BuMnLoadRequestInAHSHydraulic', 'ordValue': '1', 'type': 'single', 'condition': 'BuMn.load.request.inAHSHydraulic.4 == BUFFER', 'condition_testing': 'BuMn.load.request.inAHSHydraulic.4 == 1'}], 'type': 'customkeypadonly_text_linear', 'user_level': 3}, {'id': 'BuMnLoadRequestCfgBufferAHSOffset', 'view_id': 122, 'label': {'key': 'BUMN_LOAD_REQUEST_CFGBUFFERAHSOFFSET', 'en': 'Buffer to heat source set temperature increase', 'de': 'Temperaturanhebung Puffer zu Mischer/Wärmeerzeuger'}, 'range': None, 'testing_conditions': [{'ordName': 'BuMnLoadRequestMnIsActive', 'ordValue': '1', 'type': 'single', 'condition': 'BuMn.load.request.mnIsActive.1 == true', 'condition_testing': 'BuMn.load.request.mnIsActive.1 == 1'}, {'ordName': 'BuMnLoadRequestInAHSHydraulic', 'ordValue': '1', 'type': 'single', 'condition': 'BuMn.load.request.inAHSHydraulic.4 == BUFFER', 'condition_testing': 'BuMn.load.request.inAHSHydraulic.4 == 1'}], 'type': 'customkeypadonly_text_linear', 'user_level': 2}]

And the value I want to search: OR

Thanks

2 Answers

Here I implemented simple function contains(x, val) that returns True if x contains val somewhere inside, and False otherwise. This function recursively calls itself to search inside all sub-structures at any depth.

When searching inside dictionary I search only inside values. To search also inside keys replace piece of code contains(v, val) with contains(v, val) or contains(k, val).

Next code starts with this function, then your example x data structure follows (I re-formatted it to be pretty), and at the end of code there are some tests.

Try it online!

def contains(x, val):
    if isinstance(x, list):
        for e in x:
            if contains(e, val):
                return True
    elif isinstance(x, dict):
        for k, v in x.items():
            if contains(v, val):
                return True
    elif x == val:
        return True
    return False

x = [
    {
        "id": "BuMnLoadRequestCfgBufferRequestOnHysteresis",
        "view_id": 122,
        "label": {
            "key": "BUMN_LOAD_REQUEST_CFGBUFFERREQUESTONHYSTERESIS",
            "en": "Hysteresis to start buffer cylinder loading",
            "de": "Einschalthysterese Puffer",
        },
        "range": None,
        "testing_conditions": [
            [
                {
                    "ordName": "BuMnLoadRequestMnIsActive",
                    "ordValue": "1",
                    "type": "single",
                    "condition": "BuMn.load.request.mnIsActive.1 == true",
                    "condition_testing": "BuMn.load.request.mnIsActive.1 == 1",
                },
                "OR",
                {
                    "ordName": "BuMnLoadHydMnIsFlowControlActive",
                    "ordValue": "1",
                    "type": "single",
                    "condition": "BuMn.load.hyd.mnIsFlowControlActive.1 == true",
                    "condition_testing": "BuMn.load.hyd.mnIsFlowControlActive.1 == 1",
                },
            ],
            {
                "ordName": "BuMnLoadRequestInAHSHydraulic",
                "ordValue": "1",
                "type": "single",
                "condition": "BuMn.load.request.inAHSHydraulic.4 == BUFFER",
                "condition_testing": "BuMn.load.request.inAHSHydraulic.4 == 1",
            },
        ],
        "type": "customkeypadonly_text_linear",
        "user_level": 3,
    },
    {
        "id": "BuMnLoadRequestCfgBufferRequestOffHysteresis",
        "view_id": 122,
        "label": {
            "key": "BUMN_LOAD_REQUEST_CFGBUFFERREQUESTOFFHYSTERESIS",
            "en": "Hysteresis to stop buffer cylinder loading",
            "de": "Ausschalthysterese Puffer",
        },
        "range": None,
        "testing_conditions": [
            [
                {
                    "ordName": "BuMnLoadRequestMnIsActive",
                    "ordValue": "1",
                    "type": "single",
                    "condition": "BuMn.load.request.mnIsActive.1 == true",
                    "condition_testing": "BuMn.load.request.mnIsActive.1 == 1",
                },
                "OR",
                {
                    "ordName": "BuMnLoadHydMnIsFlowControlActive",
                    "ordValue": "1",
                    "type": "single",
                    "condition": "BuMn.load.hyd.mnIsFlowControlActive.1 == true",
                    "condition_testing": "BuMn.load.hyd.mnIsFlowControlActive.1 == 1",
                },
            ],
            {
                "ordName": "BuMnLoadRequestInAHSHydraulic",
                "ordValue": "1",
                "type": "single",
                "condition": "BuMn.load.request.inAHSHydraulic.4 == BUFFER",
                "condition_testing": "BuMn.load.request.inAHSHydraulic.4 == 1",
            },
        ],
        "type": "customkeypadonly_text_linear",
        "user_level": 3,
    },
    {
        "id": "BuMnLoadRequestCfgBufferAHSOffset",
        "view_id": 122,
        "label": {
            "key": "BUMN_LOAD_REQUEST_CFGBUFFERAHSOFFSET",
            "en": "Buffer to heat source set temperature increase",
            "de": "Temperaturanhebung Puffer zu Mischer/Wärmeerzeuger",
        },
        "range": None,
        "testing_conditions": [
            {
                "ordName": "BuMnLoadRequestMnIsActive",
                "ordValue": "1",
                "type": "single",
                "condition": "BuMn.load.request.mnIsActive.1 == true",
                "condition_testing": "BuMn.load.request.mnIsActive.1 == 1",
            },
            {
                "ordName": "BuMnLoadRequestInAHSHydraulic",
                "ordValue": "1",
                "type": "single",
                "condition": "BuMn.load.request.inAHSHydraulic.4 == BUFFER",
                "condition_testing": "BuMn.load.request.inAHSHydraulic.4 == 1",
            },
        ],
        "type": "customkeypadonly_text_linear",
        "user_level": 2,
    },
]

assert contains(x, 'OR')
assert contains(x, 'BuMnLoadRequestMnIsActive')
assert not contains(x, 'AND')

You will have to search recursively. Something like this?

from typing import Any


data = [
    {
        "id": "BuMnLoadRequestCfgBufferRequestOnHysteresis",
        "view_id": 122,
        "label": {
            "key": "BUMN_LOAD_REQUEST_CFGBUFFERREQUESTONHYSTERESIS",
            "en": "Hysteresis to start buffer cylinder loading",
            "de": "Einschalthysterese Puffer",
        },
        "range": None,
        "testing_conditions": [
            [
                {
                    "ordName": "BuMnLoadRequestMnIsActive",
                    "ordValue": "1",
                    "type": "single",
                    "condition": "BuMn.load.request.mnIsActive.1 == true",
                    "condition_testing": "BuMn.load.request.mnIsActive.1 == 1",
                },
                "OR",
                {
                    "ordName": "BuMnLoadHydMnIsFlowControlActive",
                    "ordValue": "1",
                    "type": "single",
                    "condition": "BuMn.load.hyd.mnIsFlowControlActive.1 == true",
                    "condition_testing": "BuMn.load.hyd.mnIsFlowControlActive.1 == 1",
                },
            ],
            {
                "ordName": "BuMnLoadRequestInAHSHydraulic",
                "ordValue": "1",
                "type": "single",
                "condition": "BuMn.load.request.inAHSHydraulic.4 == BUFFER",
                "condition_testing": "BuMn.load.request.inAHSHydraulic.4 == 1",
            },
        ],
        "type": "customkeypadonly_text_linear",
        "user_level": 3,
    },
    {
        "id": "BuMnLoadRequestCfgBufferRequestOffHysteresis",
        "view_id": 122,
        "label": {
            "key": "BUMN_LOAD_REQUEST_CFGBUFFERREQUESTOFFHYSTERESIS",
            "en": "Hysteresis to stop buffer cylinder loading",
            "de": "Ausschalthysterese Puffer",
        },
        "range": None,
        "testing_conditions": [
            [
                {
                    "ordName": "BuMnLoadRequestMnIsActive",
                    "ordValue": "1",
                    "type": "single",
                    "condition": "BuMn.load.request.mnIsActive.1 == true",
                    "condition_testing": "BuMn.load.request.mnIsActive.1 == 1",
                },
                "OR",
                {
                    "ordName": "BuMnLoadHydMnIsFlowControlActive",
                    "ordValue": "1",
                    "type": "single",
                    "condition": "BuMn.load.hyd.mnIsFlowControlActive.1 == true",
                    "condition_testing": "BuMn.load.hyd.mnIsFlowControlActive.1 == 1",
                },
            ],
            {
                "ordName": "BuMnLoadRequestInAHSHydraulic",
                "ordValue": "1",
                "type": "single",
                "condition": "BuMn.load.request.inAHSHydraulic.4 == BUFFER",
                "condition_testing": "BuMn.load.request.inAHSHydraulic.4 == 1",
            },
        ],
        "type": "customkeypadonly_text_linear",
        "user_level": 3,
    },
    {
        "id": "BuMnLoadRequestCfgBufferAHSOffset",
        "view_id": 122,
        "label": {
            "key": "BUMN_LOAD_REQUEST_CFGBUFFERAHSOFFSET",
            "en": "Buffer to heat source set temperature increase",
            "de": "Temperaturanhebung Puffer zu Mischer/Wärmeerzeuger",
        },
        "range": None,
        "testing_conditions": [
            {
                "ordName": "BuMnLoadRequestMnIsActive",
                "ordValue": "1",
                "type": "single",
                "condition": "BuMn.load.request.mnIsActive.1 == true",
                "condition_testing": "BuMn.load.request.mnIsActive.1 == 1",
            },
            {
                "ordName": "BuMnLoadRequestInAHSHydraulic",
                "ordValue": "1",
                "type": "single",
                "condition": "BuMn.load.request.inAHSHydraulic.4 == BUFFER",
                "condition_testing": "BuMn.load.request.inAHSHydraulic.4 == 1",
            },
        ],
        "type": "customkeypadonly_text_linear",
        "user_level": 2,
    },
]

def search(obj: Any, string_to_find: str) -> bool:
    """ Search through an object recursively to find a specific string.

    Args:
        obj (Any): The object to analyze
        string_to_find (str): The string to find

    Returns:
        bool: Whether the string was found or not
    """

    # Treat dictionaries as lists of values
    if isinstance(obj, dict):
        obj = list(obj.values())

    # Recurse for every element of a list
    if isinstance(obj, (list, tuple,)):
        for element in obj:
            if element == string_to_find or search(element, string_to_find):
                return True

    # Not found by default
    return False


found = search(data, "BuMnLoadRequestInAHSHydraulic")
print(f"String 'BuMnLoadRequestInAHSHydraulic' found: {found}")

found = search(data, "OR")
print(f"String 'OR' found: {found}")

found = search(data, "MYRANDOMSTRING")
print(f"String 'MYRANDOMSTRING' found: {found}")

Output:

String 'BuMnLoadRequestInAHSHydraulic' found: True
String 'OR' found: True
String 'MYRANDOMSTRING' found: False
Related