php retrieve multidimensional array value - php

This is my sample array value returned
array:3 [▼
"Status" => array:1 [▼
0 => "200"
]
"Data" => array:1 [▼
0 => array:1 [▼
0 => array:2 [▼
"sellerId" => array:1 [▼
0 => "TEST01"
]
"currency" => array:1 [▼
0 => "USD"
]
]
]
]
"Date" => array:1 [▼
0 => "Dec 31 2019"
]
]
My sample code to retrieve the value from the array above
foreach($json_array as $key => $json) {
if($key == "Status") {
$status = $json[0];
} else if ($key == "Date") {
$date = $json[0];
} else {
dd($json[0][0]['sellerId'][0]);
}
}
I am using the method above to retrieve the value from multidimensional array. Is there any better approaches that i can use to achieve my way?

Just do :
$status = $json_array['Status'];
$date = $json_array['Date'];
Maybe you should add some context to your question.

Related

How to Merge the results of a $match and $geoNear in one pipeline in Mongodb

I have a collection of restaurants and I want to query them with two diffrent criterias and merge them together
I have two aggregation pipelines one that is a $match and the other one that is a $geoNear ,
array:1 [▼
0 => array:1 [▼
"$match" => array:1 [▼
"$or" => array:1 [▼
0 => array:1 [▼
"$and" => array:2 [▼
0 => array:1 [▼
"country" => array:1 [▶]
]
1 => array:1 [▼
"$or" => array:1 [▼
0 => array:1 [▼
"$or" => array:1 [▶]
]
]
]
]
]
]
]
and
^ array:1 [▼
0 => array:1 [▼
"$geoNear" => array:5 [▼
"near" => array:2 [▶]
"distanceField" => "distance.calculated"
"spherical" => true
"key" => "location"
"query" => array:1 [▶]
]
]
]
I want to be able to make just one call/ in one pipeline and get ALL NON DUPLICATES restaurants. (a way to identify them it would be with the _id )
For example getting all the ones that match $match pipeline , the same with $geoNear , merge them and remove duplicates
You can use query option in $geoNear. It will include the documents which matches the condition in query.
Reference
Sample from documentation:
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },
distanceField: "dist.calculated",
maxDistance: 2,
query: { category: "Parks" }, //Query portion
includeLocs: "dist.location",
spherical: true
}
}
])

How to convert XML string to PHP array with a different structure?

I have this method that converts an XML string into a PHP array with different keys and values to fully make sense of that XML appropriately. However, when there are multiple children of the same kind, I'm not getting the desired result from the array and I'm confused on how to alter the method to do so.
This is what the method looks like:
/**
* Converts a XML string to an array
*
* #param $xmlString
* #return array
*/
private function parseXml($xmlString)
{
$doc = new DOMDocument;
$doc->loadXML($xmlString);
$root = $doc->documentElement;
$output[$root->tagName] = $this->domnodeToArray($root, $doc);
return $output;
}
/**
* #param $node
* #param $xmlDocument
* #return array|string
*/
private function domNodeToArray($node, $xmlDocument)
{
$output = [];
switch ($node->nodeType)
{
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++)
{
$child = $node->childNodes->item($i);
$v = $this->domNodeToArray($child, $xmlDocument);
if (isset($child->tagName))
{
$t = $child->tagName;
if (!isset($output['value'][$t]))
{
$output['value'][$t] = [];
}
$output['value'][$t][] = $v;
}
else if ($v || $v === '0')
{
$output['value'] = htmlspecialchars((string)$v, ENT_XML1 | ENT_COMPAT, 'UTF-8');
}
}
if (isset($output['value']) && $node->attributes->length && !is_array($output['value']))
{
$output = ['value' => $output['value']];
}
if (!$node->attributes->length && isset($output['value']) && !is_array($output['value']))
{
$output = ['attributes' => [], 'value' => $output['value']];
}
if ($node->attributes->length)
{
$a = [];
foreach ($node->attributes as $attrName => $attrNode)
{
$a[$attrName] = (string)$attrNode->value;
}
$output['attributes'] = $a;
}
else
{
$output['attributes'] = [];
}
if (isset($output['value']) && is_array($output['value']))
{
foreach ($output['value'] as $t => $v)
{
if (is_array($v) && count($v) == 1 && $t != 'attributes')
{
$output['value'][$t] = $v[0];
}
}
}
break;
}
return $output;
}
Here is some example XML:
<?xml version="1.0" encoding="UTF-8"?>
<characters>
<character>
<name2>Sno</name2>
<friend-of>Pep</friend-of>
<since>1950-10-04</since>
<qualification>extroverted beagle</qualification>
</character>
<character>
<name2>Pep</name2>
<friend-of>Sno</friend-of>
<since>1966-08-22</since>
<qualification>bold, brash and tomboyish</qualification>
</character>
</characters>
Running the method and passing that XML as its parameter, will result with this array:
array:1 [▼
"characters" => array:2 [▼
"value" => array:1 [▼
"character" => array:2 [▼
0 => array:2 [▼
"value" => array:4 [▼
"name2" => array:2 [▼
"attributes" => []
"value" => "Sno"
]
"friend-of" => array:2 [▼
"attributes" => []
"value" => "Pep"
]
"since" => array:2 [▼
"attributes" => []
"value" => "1950-10-04"
]
"qualification" => array:2 [▼
"attributes" => []
"value" => "extroverted beagle"
]
]
"attributes" => []
]
1 => array:2 [▼
"value" => array:4 [▼
"name2" => array:2 [▼
"attributes" => []
"value" => "Pep"
]
"friend-of" => array:2 [▼
"attributes" => []
"value" => "Sno"
]
"since" => array:2 [▼
"attributes" => []
"value" => "1966-08-22"
]
"qualification" => array:2 [▼
"attributes" => []
"value" => "bold, brash and tomboyish"
]
]
"attributes" => []
]
]
]
"attributes" => []
]
]
What I want it to result to is (indentation could be wrong):
array:1 [▼
"characters" => array:2 [▼
"value" => array:2 [▼
0 => [
"character" => array:1 [▼
"value" => array:4 [▼
"name2" => array:2 [▼
"attributes" => []
"value" => "Sno"
]
"friend-of" => array:2 [▼
"attributes" => []
"value" => "Pep"
]
"since" => array:2 [▼
"attributes" => []
"value" => "1950-10-04"
]
"qualification" => array:2 [▼
"attributes" => []
"value" => "extroverted beagle"
]
]
"attributes" => []
]
]
]
1 => array:2 [▼
"character" => array:1 [▼
"value" => array:4 [▼
"name2" => array:2 [▼
"attributes" => []
"value" => "Pep"
]
"friend-of" => array:2 [▼
"attributes" => []
"value" => "Sno"
]
"since" => array:2 [▼
"attributes" => []
"value" => "1966-08-22"
]
"qualification" => array:2 [▼
"attributes" => []
"value" => "bold, brash and tomboyish"
]
]
"attributes" => []
]
]
]
]
"attributes" => []
]
]
So basically, I want the characters key's value key to be an array of two items, which basically includes the 2 character keys. This is only to happen if there are many of the same element on the same branch. The way it currently is, where the character key is an array with 2 elements doesn't work in my situation.
Altering the method above to reflect my needs hasn't been possible for me yet and I'm not sure what kind of approach I should take. Altering an array like this from a DOMDocument instance seems quite complicated.
The problem is when to add in a new level and when to carry on with just adding the data. I've changed this logic, adding comments to the code to help understand what happens and when...
private function domNodeToArray($node, $xmlDocument)
{
$output = [];
switch ($node->nodeType)
{
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++)
{
$child = $node->childNodes->item($i);
$v = $this->domNodeToArray($child, $xmlDocument);
if (isset($child->tagName))
{
$t = $child->tagName;
// if (!isset($output['value'][$t]))
// {
// $output['value'][$t] = [];
// }
// If the element already exists
if (isset($output['value'][$t]))
{
// Copy the existing value to new level
$output['value'][] = [$t => $output['value'][$t]];
// Add in new value
$output['value'][] = [$t => $v];
// Remove old element
unset($output['value'][$t]);
}
// If this has already been added at a new level
elseif ( isset($output['value'][0][$t]))
{
// Add it to existing extra level
$output['value'][] = [$t => $v];
}
else {
$output['value'][$t] = $v;
}
}
else if ($v || $v === '0')
{
$output['value'] = htmlspecialchars((string)$v, ENT_XML1 | ENT_COMPAT, 'UTF-8');
}
}
if (isset($output['value']) && $node->attributes->length && !is_array($output['value']))
{
$output = ['value' => $output['value']];
}
if (!$node->attributes->length && isset($output['value']) && !is_array($output['value']))
{
$output = ['attributes' => [], 'value' => $output['value']];
}
if ($node->attributes->length)
{
$a = [];
foreach ($node->attributes as $attrName => $attrNode)
{
$a[$attrName] = (string)$attrNode->value;
}
$output['attributes'] = $a;
}
else
{
$output['attributes'] = [];
}
break;
}
return $output;
}
I've tried it with...
<?xml version="1.0" encoding="UTF-8"?>
<characters>
<character>
<name2>Sno</name2>
<friend-of>Pep</friend-of>
<since>1950-10-04</since>
<qualification>extroverted beagle</qualification>
</character>
<character>
<name2>Pep</name2>
<friend-of>Sno</friend-of>
<since>1966-08-22</since>
<qualification>bold, brash and tomboyish</qualification>
</character>
<character>
<name2>Pep2</name2>
<friend-of>Sno</friend-of>
<since>1966-08-23</since>
<qualification>boldish, brashish and tomboyish</qualification>
</character>
</characters>
to check that the <character> elements are all added to the right level.
I've done some changes to your function but I'm not sure if this is what you need.
private function domNodeToArray($node, $xmlDocument)
{
$output = ['value' => [], 'attributes' => []];
switch ($node->nodeType) {
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
$child = $node->childNodes->item($i);
$v = $this->domNodeToArray($child, $xmlDocument);
if (isset($child->tagName)) {
$t = $child->tagName;
if (isset($output['value'][$t])) {
$output['value'][] = [$t => $output['value'][$t]];
$output['value'][] = [$t => $v];
unset($output['value'][$t]);
} else {
$output['value'][$t] = $v;
}
} elseif (($v && is_string($v)) || $v === '0') {
$output['value'] = htmlspecialchars((string)$v, ENT_XML1 | ENT_COMPAT, 'UTF-8');
}
}
if ($node->attributes->length) {
foreach ($node->attributes as $attrName => $attrNode) {
$output['attributes'][$attrName] = (string) $attrNode->value;
}
}
break;
}
return $output;
}
Output
array:1 [▼
"characters" => array:2 [▼
"value" => array:2 [▼
0 => array:1 [▼
"character" => array:2 [▼
"value" => array:4 [▼
"name2" => array:2 [▼
"value" => "Sno"
"attributes" => []
]
"friend-of" => array:2 [▼
"value" => "Pep"
"attributes" => []
]
"since" => array:2 [▼
"value" => "1950-10-04"
"attributes" => []
]
"qualification" => array:2 [▼
"value" => "extroverted beagle"
"attributes" => []
]
]
"attributes" => []
]
]
1 => array:1 [▼
"character" => array:2 [▼
"value" => array:4 [▼
"name2" => array:2 [▼
"value" => "Pep"
"attributes" => []
]
"friend-of" => array:2 [▼
"value" => "Sno"
"attributes" => []
]
"since" => array:2 [▼
"value" => "1966-08-22"
"attributes" => []
]
"qualification" => array:2 [▼
"value" => "bold, brash and tomboyish"
"attributes" => []
]
]
"attributes" => []
]
]
]
"attributes" => []
]
]

laravel collections->keyBy finds similar keys

laravel 5.5
here is the collections:
$collections = collect(['name' => 'Rob'], ['nickname' => 'Robby']);
the both methods:
$collections->keyBy('name')
$collections->keyBy('nickname')
return equil result
Collection {#246 ▼
#items: array:1 [▼
"" => "Rob"
]
}
as me this looks like wrong...
I Think You Should pass one parameter as an array .. Try This
$collections = collect([['name' => 'Rob'], ['nickname' => 'Robby']]);
Your problem is that your collection is not well formatted, do it like this:
$collections = collect([ //main collection array
[ 'name' => 'Rob1', 'nickname' => 'Robby1' ] //object 0 inside collection array with well formated keys => values
]);
Now when you use:
$collections->keyBy('name')
$collections->keyBy('nickname')
It will work as spected
so results are
Collection {#246 ▼
#items: array:2 [▼
"Rob" => array:1 [▼
"name" => "Rob"
]
"" => array:1 [▼
"nickname" => "Robby"
]
]
}
and
Collection {#246 ▼
#items: array:2 [▼
"" => array:1 [▼
"name" => "Rob"
]
"Robby" => array:1 [▼
"nickname" => "Robby"
]
]
}
still looks invalid searching in collections...
and
$collections->keyBy('nick')
returns
Collection {#246 ▼
#items: array:1 [▼
"" => array:1 [▼
"nickname" => "Robby"
]
]
}

Fill array with same data in php

I have an array with some data that returns me from the database, the problem is that not all the keys are associated, I should fill the missing keys with data to 0.
My array is by default is:
array:1 [▼
9 => array:2 [▼
4 => array:3 [▼
"Orange" => array:3 [▼
"price" => "600.00"
"total" => "690.00"
]
"Apple" => array:3 [▼
"price" => "650.00"
"total" => "870.00"
]
"Banana" => array:3 [▼
"price" => "50"
"total" => "40"
]
]
21 => array:1 [▼
"Apple" => array:3 [▼
"price" => "44"
"total" => "33"
]
]
]
]
The array should have the same structure but with data at 0
Result:
array:1 [▼
9 => array:2 [▼
4 => array:3 [▼
"Orange" => array:2 [▼
"price" => "600.00"
"total" => "690.00"
]
"Apple" => array:2 [▼
"price" => "650.00"
"total" => "870.00"
]
"Banana" => array:2 [▼
"price" => "50"
"total" => "40"
]
]
21 => array:3 [▼
"Apple" => array:2 [▼
"price" => "44"
"total" => "33"
],
"Orange" => array:2 [▼
"price" => "0"
"total" => "0"
],
"Banana" => array:2 [▼
"price" => "0"
"total" => "0"
]
]
]
]
The "for" below modify each array with adding any new value and also avoid duplicate values. Basically, it finds the differences and then merge that, setting the first array to clone each array.
$fruits = array (
1 => array('Manzana', 'Naranja', 'Pera'),
2 => array('Pera', 'Sandia'),
3 => array('Manzana', 'Melocotones')
);
print_r($fruits);
for ($i = 1; $i <= count($fruits)-1; $i++) {
$result = array_diff($fruits[1], $fruits[1+$i]);
$merge = array_merge($fruits[1+$i], $result);
$fruits[1+$i] = $merge;
$fruits[1] = $merge;
}
print_r($fruits);
?>
Here to see how run it!
https://repl.it/KqUi/3
If you will always use the first element as boilerplate you can do something like this:
$boilerplate = reset($array);
array_walk_recursive($boilerplate, function (&$value) {
$value = 0;
});
$array = array_map(function ($items) use ($boilerplate) {
return array_merge($items, array_diff_key($boilerplate, $items));
}, $array);
Here is working demo.

Merge two array to create an associative array

I have a php array something like this:
array:7 [▼
"id" => 13
"agent_id" => 1
"reserved_by" => 1
"vehicle_type" => "["Bus","Car"]"
"no_of_vehicle" => "["2","1"]"
"created_at" => "2017-06-13 05:46:49"
"updated_at" => "2017-06-13 05:46:49"
]
Here, vehicle_type and no_of_vehicle are in json_encode format. In the above case,
By json_decode I can get two arrays like this
vehicle_type
dd(json_decode($data->vehicle_type));
array:2 [▼
0 => "Bus"
1 => "Car"
]
no_of_vehicle
dd(json_decode($data->no_of_vehicle));
array:2 [▼
0 => "2"
1 => "1"
]
Now, what I want is to create an associative array of vehicle type and number equals 1.
array:3 [▼
Bus => "1"
Bus => "1"
Car => "1"
]
It's impossible as all you say because of unique key. But, Is to possible to make similar array with nested like:
array:3 [▼
array:1 [▼
Bus => "1"
]
array:1 [▼
Bus => "1"
]
array:1 [▼
Bus => "1"
]
]
That will be fine for me
Any idea, I am using laravel 5.3
Thanks
array:3 [▼
Bus => "1"
Bus => "1"
Car => "1"
]
It's impossible, because the keys must unique
you can make it to
["Bus", "Bus", "Car"]
or
["Bus" => 2, "Car" => 1]
Answer to updated question
You can do like this:
$array = [
"id" => 13,
"agent_id" => 1,
"reserved_by" => 1,
"vehicle_type" => array("Bus", "Car"),
"no_of_vehicle" => array("2", "1"),
"created_at" => "2017-06-13 05:46:49",
"updated_at" => "2017-06-13 05:46:49",
];
$result = [];
foreach ($array["vehicle_type"] as $key => $vehicle) {
$num = intval($array["no_of_vehicle"][$key]);
for ($i = 1; $i <= $num; $i++) {
$result[] = array($vehicle => "1");
}
}
the $result will be:
array:3 [▼
0 => array:1 [▼
"Bus" => "1"
]
1 => array:1 [▼
"Bus" => "1"
]
2 => array:1 [▼
"Car" => "1"
]
]
I would create an array like that :
array[
{
vehicle_type => 'Bus',
no_of_vehicle => 2,
},
{
vehicle_type => 'Car',
no_of_vehicle => 1,
}
]
or
array['Bus_1', 'Bus_2', 'Car_1']

Categories