Home > Back-end >  PHP How to evaluate a recursive json object contains true and false values
PHP How to evaluate a recursive json object contains true and false values

Time:03-08

I'm working on a php script that evaluates an object into true or false. The object itself can be nested and contains many objects, for example:

{
    "nodeType": "and",
    "0": {
        "nodeType": "or",
        "0": {
            "nodeType": "or",
            "1": false,
            "2": true
        },
        "3": false
    },
    "4": true
}

The previous object should be evaluated to true. It can be nested as well, for example:

{
    "nodeType": "and",
    "0": {
        "nodeType": "or",
        "0": {
            "nodeType": "and",
            "0": {
                "nodeType": "or",
                "1": false,
                "2": true
            },
            "2": true
        },
        "3": false
    },
    "4": true
}

I already have a working script that works fine with the help of trincot The script is:

    public function findAnswer($expr) {
        if (is_bool($expr)) return $expr; // Base case
        // If OR, we can stop when we find true (and return true). 
        // If AND, we can stop when we find false (and return false).
        // if($expr["nodeType"] == "not"){
        //     return ! $expr;
        // }
        if($expr["nodeType"] == "or"){
            $search = true;
        }
        else{
            $search = false;
        }
        foreach ($expr as $key => $value) {
            if ($key !== "nodeType" && $this->findAnswer($value) === $search) {
                
                return $search;
            }
            
        }
        // If that never happened, return the opposite (false for OR, true for AND)
        return !$search;
    }

The problem is that the script doesn't work when there is not as nodeType. example:

{
    "nodeType": "and",
    "0": {
        "nodeType": "or",
        "0": {
            "nodeType": "not",
            "1": false,
        },
        "3": false
    },
    "4": false
}

The previous object should be evaluated to false.

Any suggestions to improve the script to work also with not nodeTypes?

Edit: The answer works with some cases but not with the following:

{
    "nodeType": "and",
    "0": {
        "nodeType": "or",
        "0": {
            "nodeType": "and",
            "0": {
                "nodeType": "not",
                "1": true
            },
            "2": true
        },
        "3": false
    },
    "4": true
}

This is evaluated to true while it should be evaluated to false.

CodePudding user response:

When the operator is "not", then we could consider the other argument(s) as arguments of a NAND logical operator. So if all arguments are false then it will be evaluated as true, and false otherwise. If you will never pass more than one argument to a NOT operator, then this doesn't really make a difference, but it is nice to make it work also with some logic when more arguments would need to be supported.

Here is the suggested code:

public function findAnswer($expr) {
    if (is_bool($expr)) return $expr; // Base case
    // If OR, we can stop when we find true (and return true). 
    // If NAND or NOT, we can stop when we find false (and return false).
    // If NOT, negate the outcome. When multiple arguments, perform a NOR operator
    $negate = $expr["nodeType"] == "not";
    $search = $expr["nodeType"] == "or";
    foreach ($expr as $key => $value) {
        if ($key !== "nodeType" && $this->findAnswer($value) === $search) {
            return $search !== $negate;
        }
    }
    // If that never happened, return the opposite (false for OR, true for AND)
    return $search === $negate;
}
  • Related