I'm working on a Laravel/php app and I have this array where I want to collect the final result:
[
{
"nodeType": "or",
"0": {
"nodeType": "and",
"0": {
"nodeType": "and",
"1": true,
"2": false
},
"3": true
},
"2": {
"nodeType": "or",
"4": false,
"5": true
}
}
]
I would like to be able to collect the final value which is either True or False. The array itself could contain any number of children, for example:
[
{
"nodeType": "or",
"0": {
"nodeType": "and",
"0": {
"nodeType": "or",
"0": {
"nodeType": "and",
"1": true,
"2": false
},
"3": true
},
"3": true
},
"2": {
"nodeType": "or",
"4": false,
"5": true
}
}
]
What would be the best way to go around this? I think loops don't work since the depth of the array is not fixed.
Edit 1:
to answer some of the questions in the comments. The keys have no importance. the nodes has always two values. But a value could have its two values as in the second example.
The outer level is an array but this array has only one entry. So it can simply be used as array[0] to get to the json object.
Edit 2:
The result for the following array should be false but the first answer returns true.
{
"nodeType": "and",
"0": {
"nodeType": "and",
"0": {
"nodeType": "and",
"1": true,
"2": false
},
"3": true
},
"2": {
"nodeType": "or",
"4": false,
"5": true
}
}
The nodetype can be either and or or. It is not always as written in the examples above.
You could use a recursive function, like this:
function deduct($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).
$search = $expr["nodeType"] == "or";
foreach ($expr as $key => $value) {
if ($key !== "nodeType" && deduct($value) === $search) return $search;
}
// If that never happened, return the opposite (false for OR, true for AND)
return !$search;
}
Example call using your second JSON as input:
$json = '[{"nodeType": "or","0": {"nodeType": "and", "0": {"nodeType": "or", "0": {"nodeType": "and","1": true,"2": false},"3": true},"3": true},"2": {"nodeType": "or","4": false,"5": true}}]';
$obj = json_decode($json, true)[0]; // The outer level is an array: unwrap it.
var_dump(deduct($obj));
Output:
bool(true)
Related
I have a multidimensional array with over 200 nested objects which some have children and some don't.
I'm trying to add empty children to where leaf: false and children don't exist.
[{
"id": "GRP-25",
"text": "Name 1",
"leaf": false,
"children": [{
"id": "APP-222",
"text": "Another name",
"leaf": true
}]
},
{
"id": "GRP-25",
"text": "Name 2",
"leaf": false,
"children": [] // <- missing, need to add empty children
}
]
function addEmptyChildren(array &$data)
{
foreach ($data as $k => $v)
{
// recursive call
if (is_array($v)) {
addEmptyChildren($data[$k]);
continue;
}
if ($data['leaf'] === false && !property_exists('children', $k)) {
$data['children'] = [];
}
}
}
addEmptyChildren($result);
I think I see the problem. Based on is_array(), $data['leaf'], etc., it looks like the function is meant to deal with an array of arrays, probably from json_decode($json, true), rather than an array of objects. If that's the case, then property_exists is not the right way to check for children.
Instead of this:
if ($data['leaf'] === false && !property_exists('children', $k)) {
use isset() or array_key_exists() instead.
if ($data['leaf'] === false && !isset($data['children'])) {
A lot more going on in your loop than appears to be necessary.
$str = '[{
"id": "GRP-25",
"text": "Name 1",
"leaf": false,
"children": [{
"id": "APP-222",
"text": "Another name",
"leaf": true
}]
},
{
"id": "GRP-25",
"text": "Name 2",
"leaf": false
}
]';
$result = json_decode($str);
if (json_last_error() !== 0){echo json_last_error_msg();}
#print_r($result);
function addEmptyChildren(array &$data)
{
foreach ($data as $k => $v) {
if ($v->leaf === false && !isset($v->children)) {
$v->children = [];
}
}
}
addEmptyChildren($result);
echo json_encode($result, JSON_PRETTY_PRINT);
RESULT
[
{
"id": "GRP-25",
"text": "Name 1",
"leaf": false,
"children": [
{
"id": "APP-222",
"text": "Another name",
"leaf": true
}
]
},
{
"id": "GRP-25",
"text": "Name 2",
"leaf": false,
"children": []
}
]
We have 2 arrays and we want to replace the values from the second array to the first array, it goes well, except one key it's duplicating..
The arrays:
Array 1
[
{
"1": 0
},
{
"2": 0
},
{
"3": 0
},
{
"4": 0
},
{
"5": 0
},
{
"6": 0
},
{
"7": 0
},
{
"8": 0
},
{
"9": 0
},
{
"10": 0
},
{
"11": 0
},
{
"12": 0
}
]
Array 2
[
{
"2": 4526
},
{
"3": 81
},
{
"4": 20
}
]
we proceed with
array_replace($array1, $array2);
It should return updates on the values with the key 2, 3 and 4 - however we receive this result:
[
[
{
"2": 4526
},
{
"3": 81
},
{
"4": 20
},
{
"4": 0
},
{
"5": 0
},
{
"6": 0
},
{
"7": 0
},
{
"8": 0
},
{
"9": 0
},
{
"10": 0
},
{
"11": 0
},
{
"12": 0
}
]
]
There duplicate of key with number 4, and the key with number 1 is missing at all.
Any advice please?
guys help me I'm a bit confused how my code producing an extra property to my json result see below:
$connect=mysqli_connect("localhost", "root", "", "thecmlco_widget");
$query = "SELECT * FROM widgetdb";
$result = mysqli_query($connect,$query);
$rows = array();
while($r = mysqli_fetch_array($result)) {
$rows[] = $r;
}
echo json_encode($rows);
mysqli_close($connect);
here is the result with an extra property 0 , 1 , 2 , 3 , 4 ,5 and I don't know why its creating those extra property.
[
{
"0": "1",
"1": "Vacation",
"2": "http://trilogy.editor.multiscreensite.com/preview/dm-theme-1000772-en-291",
"3": "https://dd-cdn.multiscreensite.com/themes-panel/preview/vacation.jpg",
"4": "1000772",
"5": "0",
"id": "1",
"template_name": "Vacation",
"preview_url": "http://trilogy.editor.multiscreensite.com/preview/dm-theme-1000772-en-291",
"thumbnail_url": "https://dd-cdn.multiscreensite.com/themes-panel/preview/vacation.jpg",
"templade_id": "1000772",
"can_build_from_url": "0"
},
{
"0": "2",
"1": "Product",
"2": "https://irp-cdn.multiscreensite.com/ce1f372c/siteTemplateIcons/Mstzqt8GTRSxzCt6QTue_BigPreview_iotech.png",
"3": "https://irp-cdn.multiscreensite.com/ce1f372c/siteTemplateIcons/Mstzqt8GTRSxzCt6QTue_BigPreview_iotech.png",
"4": "1003040",
"5": "0",
"id": "2",
"template_name": "Product",
"preview_url": "https://irp-cdn.multiscreensite.com/ce1f372c/siteTemplateIcons/Mstzqt8GTRSxzCt6QTue_BigPreview_iotech.png",
"thumbnail_url": "https://irp-cdn.multiscreensite.com/ce1f372c/siteTemplateIcons/Mstzqt8GTRSxzCt6QTue_BigPreview_iotech.png",
"templade_id": "1003040",
"can_build_from_url": "0"
}
]
Use mysqli_fetch_assoc() instead of mysqli_fetch_array() function to get rows as associative array
I have this piece of code to get a difference between two arrays of objects:
$diff = array_udiff($a, $b,
function($obj_a, $obj_b) {
return $obj_a->id - $obj_b->id;
}
);
$a is
[
{
"id": "7",
"attribute": "instagram"
},
{
"id": "8",
"attribute": "snapchat"
},
{
"id": "9",
"attribute": "facebook"
}
]
$b is
[
{
"id": "7",
"attribute": "instagram",
"value": "somevalue"
}
]
$diff should return array of objects
[
{
"id": "8",
"attribute": "snapchat"
},
{
"id": "9",
"attribute": "facebook"
}
]
And it does, but only when $b is an empty array. The result is then correct (I get an array of objects, the $a, because $b is empty).
But when at least one object is present in the $b, the $diff is returning to me the following which I don't want.
{
"1": {
"id": "8",
"attribute": "snapchat"
},
"2": {
"id": "9",
"attribute": "facebook"
}
}
How do I get an array of objects in the result instead of the above? And why there is a difference between the two results? Thanks.
You just need to use $diff = array_values($diff); before you json_encode so that the indexes will start at zero.
When you do the array_udiff, the keys of $a are preserved, so $diff has keys starting at 1 instead of 0. In order for json_encode to encode an array as a JSON array instead of a JSON object, the keys must be sequential and start at zero. array_values will reindex the array so that this condition will be met.
Just to be clear, even if other items were removed from the array instead of the first one, so that the indexes still started with zero, you would still need to reindex $diff because of the missing keys.
I need to query based on key's that all equal the same thing, let's say the following is an order, and that order contains three products. I need to query orders, that have products, that have a specific status all equal to true. Each product is stored, with a mongo id as its key, so I don't actually know it's key name, Example: (obviously I've shortened the keys)
{
"_id" : "foo",
"products": {
"123": {
"status": {
"a": false,
"b": true,
"c": true,
},
},
"213": {
"status": {
"a": true,
"b": true,
"c": true,
},
},
"321": {
"status": {
"a": false,
"b": false,
"c": true,
},
}
},
}
Here's what I've tried:
$this->database->$collection->find(
array('_id' => 'foo', 'products.$.status.c' => true)
);
I'd expect the above, to return the complete order in the example, as the status 'c' inside each product is true, if I were to perform the same query, but with 'a' or 'b' as the status query, it wouldn't return it.
I'm not really sure how to do this, obviously the above didn't work, so my question is, how can I match on multiple sub keys of an array of objects that I do not know the key name?
You want an array of documents, not an object with the id as its key. The $ positional operator doesn't work on objects.
{
"_id" : "foo",
"products": [
{
id: "123"
"status": {
"a": false,
"b": true,
"c": true,
},
},
{
id: "213"
"status": {
"a": true,
"b": true,
"c": true,
},
},
{
id: "321"
"status": {
"a": false,
"b": false,
"c": true,
},
}
]
}
Your query needs to look like this:
$this->database->$collection->find(
array('_id' => 'foo', 'products.status.c' => true)
);
This returns the cursor at the first 'product' that matches your query
and on udpate.
$this->database->$collection->find(
array('_id' => 'foo', 'products.status.c' => true),
array('products.$.hello' => 'world')
);
This updates only that sub document. The only time you should use objects is if you know what the keys will be. Like status, or address... but if key is a variable as well, it gets really tricky, really quickly.