I am doing a request to an API and for each request I get an array with the BrowseNodes back. Inside this array I get this result:
array:1 [
"BrowseNode" => array:3 [
"BrowseNodeId" => "2502033031"
"Name" => "OBD-II Diagnosewerkzeuge"
"Ancestors" => array:1 [
"BrowseNode" => array:3 [
"BrowseNodeId" => "5142250031"
"Name" => "Motorwerkzeuge & Zubehör"
"Ancestors" => array:1 [
"BrowseNode" => array:3 [
"BrowseNodeId" => "2502064031"
"Name" => "Werkzeuge"
"Ancestors" => array:1 [
"BrowseNode" => array:4 [
"BrowseNodeId" => "79899031"
"Name" => "Kategorien"
"IsCategoryRoot" => "1"
"Ancestors" => array:1 [
"BrowseNode" => array:2 [
"BrowseNodeId" => "78191031"
"Name" => "Auto & Motorrad"
]
]
]
]
]
]
]
]
]
]
If this would be a fixed array which always had this length it would be easy for me to get the last BrowseNode Array and the value with the key "Name". In this case it would be the this one "Name" => "Auto & Motorrad".
However, because a category can have one or more nested arrays, it is not static...
That means I have to find a solution to always get the most nested array and from this one the name to get the category. Because it is dynamic data, I don't know how to solve that. I just know I always have to get the BrowseNode and then inside the BrowseNode array. I have to get the Ancestors and inside this Ancestors again. I have to get the BrowseNode array until I arrived at the last BrowseNode array and the get the name.
So, I have to iterate through my array until the BrowseNode array doesn't have an Ancestors array anymore and the get the name of this BrowseNode array.
Do you guys have any idea on how to do this?
I guess you can use recursion to achieve that.
On each object, search for Ancestors, if not found return the name, else do so again on the Ancestors.
Consider the following code:
$arr = array("BrowseNode" => array("BrowseNodeId" => "1", "Ancestors" => array("BrowseNode" => array("BrowseNodeId" => "2", "Ancestors" => array("BrowseNode" => array("BrowseNodeId" => "3"))))));
function getLastName($elem) {
$elem = $elem["BrowseNode"];
if (!array_key_exists("Ancestors", $elem))
return $elem['BrowseNodeId'];
else return getLastName($elem["Ancestors"]);
}
echo getLastName($arr);
Notice that this code return id instead of your Name - small modification I leave to you...
There might be a more "correct" way of doing this but since I'm writing this on my phone on a plane, you'll have to forgive my not being able to proof check my answer. But you could do a recursive function, like...
function recurseArray($browseNode)
{
if(isset($browseNode["Ancestors"])) {
recurseArray($browseNode["Ancestors"]["browseNode"])
} else {
// Do whatever you want with the last iteration
}
}
Hope that makes sense!
Related
I am using this package to handle hierarchy data in Laravel: https://github.com/lazychaser/laravel-nestedset
Their is an implemented functionality which provides the opportunity to create new data with a multidimensional array. So I have the following sample array (of a file/directory hierarchy):
array:3 [
"name" => "Folder1"
"type" => "folder"
"children" => array:2 [
0 => array:2 [
"name" => "test1.txt"
"type" => "txt"
]
1 => array:3 [
"name" => "Folder1.1"
"type" => "folder"
"children" => array:2 [
0 => array:2 [
"name" => "file.png"
"type" => "png"
]
1 => array:3 [
"name" => "folder1.1.1"
"type" => "folder"
"children" => array:1 [
0 => array:2 [
"name" => "file.txt"
"type" => "txt"
]
]
]
]
]
]
]
But their are directories with more than 10GB of data which means they have a much higher complexity than the shown example with a deep hierarchy. The database is already filled with over a million rows. And if I try to insert a new array the MySQL immediately runs on 100% CPU and needs about 20 minutes to insert that new structure into the database.
The reason is because it needs to calculate LEFT and RIGHT for nested set considering already existent data in the table.
Is there a more efficient way to insert such hierarchies into the database?
Quick example of adding the left and right items to the various arrays (assuming that the lowest level of the arrays is a row of items, so no need add a left and right to these individual items).
Something like this could be used to add the values
<?php
function array_left_right (&$array, &$counter = 1)
{
if (is_array($array))
{
$array['left'] = $counter++;
foreach($array as $array_key=>&$array_item)
{
array_left_right($array_item, $counter);
}
$array['right'] = $counter++;
}
}
$fred = array(array(array('a', 'b'), array('c', 'd'), array('e', 'f'), array('g', 'h')),array(array('aa', 'ab'), array('ac', 'ad'), array('ae', 'af'), array('ag', 'ah')));
array_left_right($fred);
print_r($fred);
I have issue where I have array like this:
array1: [
1 => array:1 [
"category" => array2 [
"id" => 1
"category_name" => portable/fun
]
]
I wish I could split values of "category_name" into another subarray with two separate values "portable" and "fun".
It should look something like this:
array1: [
1 => array:1 [
"category" => array2 [
"id" => 1
"category_name" => array:2 [
1 => portable
2 => fun
]
]
]
I know how to split this one value but how can I push it as a subarray like in my example?
Or maybe there is another simplified way to get result I need?
You can use recursive approach to achieve the same,
array_walk_recursive ($arr, function(&$v,$k){
if($k == 'category_name'){ // check recursively if $k is category_name
$v = explode("/",$v); // replace value with explode result
}
});
Demo.
I have a multi-dimensional array that is keyed by uuid's and need to slice/pop/unset an element by uuid (i.e., if I had a410463e-7fe2-4fba-8733-a812c0ee8c54 and wanted to remove that item by that uuid) so that the result is essentially the same minus the one item that was removed:
array:5 [
"5fc29794-9e08-4944-ba6d-4a5fcde5c88b" => array:3 [
"id" => "5fc29794-9e08-4944-ba6d-4a5fcde5c88b"
"name" => "fuga"
"value" => 0
]
"a410463e-7fe2-4fba-8733-a812c0ee8c54" => array:3 [
"id" => "a410463e-7fe2-4fba-8733-a812c0ee8c54"
"name" => "nihil"
"value" => 0
]
"c141d973-91fe-4227-8985-04bd0665f4a8" => array:3 [
"id" => "c141d973-91fe-4227-8985-04bd0665f4a8"
"name" => "eaque"
"value" => 0
]
"17030897-1aa9-487d-a4be-d574dd0c9d9b" => array:3 [
"id" => "17030897-1aa9-487d-a4be-d574dd0c9d9b"
"name" => "eveniet"
"value" => 3
]
"901d9f8f-573f-444f-8562-0cdf5888ba6e" => array:3 [
"id" => "901d9f8f-573f-444f-8562-0cdf5888ba6e"
"name" => "in"
"value" => 6
]
]
I know how to slice by index, but am having trouble finding resources on how this might be achieved. This is for a phpunit test. I've tried unset, but can't seem to store that in a variable or just call it in an assertion:
unset($array1[$id]);
unset($array2[$id]);
Does not persist the change.
$newUnchanged = unset($array1[$id]);
$oldUnchanged = unset($array2[$id]);
Throws syntax error, unexpected 'unset' error. Ultimately I want to assert that all of the unchanged items remained the same as prior to a single item being updated. I've also tried this ugly business which is removing a single item, but not the correct one:
$keyOne = array_search($id, array_keys($array1), true);
$oldUnchanged = array_slice($array1, $keyOne, null, true);
$keyTwo = array_search($id, array_keys($array2), true);
$newUnchanged = array_slice($array2, $keyTwo, null, true);
// Shows that the item that I wanted to slice still exists in both arrays
dd($id, $oldUnchanged, $newUnchanged);
// ^ Causes this test to fail
$this->assertEquals($oldUnchanged, $newUnchaged);
I figured out I have to clone the arrays before I can unset them
$oldUnchanged = $array1;
unset($oldUnchanged[$id]);
$newUnchanged = $array2;
unset($newUnchanged[$id]);
In input I have such an array:
array:1 [
"prizes" => array:1 [
1 => array:2 [
"prize_id" => "1"
"priority" => "1"
"some_fields" => "some_value"
]
]
]
In controller, I try to get only two fields:
$request->only([
'prizes.*.priority',
'prizes.*.prize_id'
]);
but i should get this:
array:1 [
"prizes" => array:1 [
"*" => array:2 [
"priority" => array:1 [
0 => "1"
]
"prize_id" => array:1 [
0 => "1"
]
]
]
]
How to get array with needed fields?
You are getting an array as the result because you are using .*. which is saying get ALL priorities for the prizes, which is why it is returning an array instead.
If you use the dot notation, you will access the only priority for the prize.
Like so:
prizes.priority
If you would like to validate for EVERY prize that you get coming in, you will use *. before hand to access each array, like so:
*.prizes.priority
Edit: bit more information here https://laravel.com/docs/master/validation#validating-arrays
My goal is to be able to update a key value inside of an array inside of an array and I'm don't know if I'm using the right php array function.
BEFORE:
array:2 [
"week_number" => 1
"games" => array:1 [
0 => array:3 [
"game_number" => 1
"umpires" => []
"teams" => []
]
]
]
AFTER:
array:2 [
"week_number" => 1
"games" => array:1 [
0 => array:3 [
"game_number" => 1
"umpires" => []
"teams" => [1,2]
]
]
]
Test Class:
private function validParams($overrides = [])
{
return array_merge_recursive([
'week_number' => 1,
'games' => [[
'game_number' => 1,
'umpires' => [],
'teams' => [],
]]
], $overrides);
}
$response = $this->actingAs($this->authorizedUser)
->post(route('games.store', ['week' => $this->week->id]), $this->validParams([
'games' => [][
[
'teams' => [1,2]
]
]
]));
If you want to update the keys... typing $array['new_key'] = $array['old_key'] will duplicate the value with 2 sets of keys.
You have a few options here. Either you create a new array and just set your desired keys or work with array_keys and array_values and mix them up... your choice
http://php.net/manual/en/ref.array.php
See the list above, there are a lot of array functions you can use... see the two above and array_map... there is virtually a great number of ways you can do this. See how your problem is best handled after reviewing the documentation.
Good luck!
This is the moment where you need unset(): Adding a value with a different key will not update or overwrite the old value but simply add another key-value pair.
Hence, add the new value fist, then unset the old one. We can use To array_walk to itterate over the array:
array_walk($array, function (& $item) {
$item['new_key'] = $item['old_key'];
unset($item['old_key']);
});
Take note of the & reference operator in the lambda function: it ensures we are working on the original array and not a copy of it.
I found this as a solution.
private function validParams($overrides = [])
{
return array_replace_recursive([
'week_number' => 1,
'games' => [
0 => [
'game_number' => 1,
'umpires' => [],
'teams' => [],
]
]
], $overrides);
}
->post(route('games.store', ['week' => $this->week->id]), $this->validParams([
'games' => [
0 => [
'teams' => [1,2]
]
]
]));