I've searched stackoverflow and found many similar questions which where solved with array_slice
, array_splice
and the occasional array_merge
, but none of these worked for me and I'm stumped. I must be doing something wrong, but can't figure out what exactly.
My problem: I have a nested associative array representing a menu structure. It looks like this
$this->navigation_array=[
"CATEGORY_MAIN"=>[
"Page1"=>"page1.php",
"Page2"=>"page2.php",
"Page3"=>"page3.php",
"Page4"=>"page4.php"
],
"CATEGORY_NEW"=>[
"Page1"=>"page1_edit.php",
"Page2"=>"page2_edit.php",
"Page3"=>"page3_edit.php"
],
"CATEGORY_EMPTY1"=>[],
"CATEGORY_EMPTY2"=>[],
"SEARCH"=>[
"Page1"=>"page1_search.php",
"Page2"=>"page2_search.php",
"Page3"=>"page3_search.php"
],
"BACK"=>["Home"=>"index.php"]
];
Now I need a function to add a new category at a given position from either the beginning or the end of the navigation_array. So, either $MENU->category_add("test",2)
or $MENU->category_add("test",-1)
What I tried so far fails, even though I tried several different approaches from here, here or here. The current, non-functional, iteration looks like this
public function category_add(string $category,int $position=0): bool{
if(array_key_exists($category,$this->navigation_array))return false;
if($position!=0){
$category_array=array($category=>[]);
array_splice($this->navigation_array,$position,0,$category_array);
}else $this->navigation_array[$category]=array(); //simply append if pos is 0
return true;
}
It does insert at the correct position when I call it with $MENU->category_add("test",2)
or $MENU->category_add("test",-1)
but what is inserted is [0] => Array ( )
instead of ["test"] => Array ( )
.
The resulting navigation array thus looks like this:
Array ( [CATEGORY_MAIN] => Array ( [Page1] => page1.php [Page2] => page2.php [Page3] => page3.php [Page4] => page4.php ) [CATEGORY_NEW] => Array ( [Page1] => page1_edit.php [Page2] => page2_edit.php [Page3] => page3_edit.php ) [CATEGORY_EMPTY1] => Array ( ) [CATEGORY_EMPTY2] => Array ( ) [SEARCH] => Array ( [Page1] => page1_search.php [Page2] => page2_search.php [Page3] => page3_search.php ) [0] => Array ( ) [BACK] => Array ( [Home] => index.php ) )
But should look like
Array ( [CATEGORY_MAIN] => Array ( [Page1] => page1.php [Page2] => page2.php [Page3] => page3.php [Page4] => page4.php ) [CATEGORY_NEW] => Array ( [Page1] => page1_edit.php [Page2] => page2_edit.php [Page3] => page3_edit.php ) [CATEGORY_EMPTY1] => Array ( ) [CATEGORY_EMPTY2] => Array ( ) [SEARCH] => Array ( [Page1] => page1_search.php [Page2] => page2_search.php [Page3] => page3_search.php ) [test] => Array ( ) [BACK] => Array ( [Home] => index.php ) )
I know it's probably something pretty minor or silly that I'm overlooking, but I've stared at this so long, I'm obviously blind to it. Could somebody be so kind and give me a hint?
Edit
So according to the php doc, ""Note: Keys in the replacement array are not preserved." array_splice
does not work. But there must be another way to somehow achieve this, right?
CodePudding user response:
Try this code, it has two functions category_add
which is calling arrayInsert
custom function, we can add a whole new category as well as insert new page inside of existing category.
<?php
$navigation_array = [
"CATEGORY_MAIN" => [
"Page1" => "page1.php",
"Page2" => "page2.php",
"Page3" => "page3.php",
"Page4" => "page4.php"
],
"CATEGORY_NEW" => [
"Page1" => "page1_edit.php",
"Page2" => "page2_edit.php",
"Page3" => "page3_edit.php"
],
"CATEGORY_EMPTY1" => [],
"CATEGORY_EMPTY2" => [],
"SEARCH" => [
"Page1" => "page1_search.php",
"Page2" => "page2_search.php",
"Page3" => "page3_search.php"
],
"BACK" => [
"Home" => "index.php"
]
];
function category_add(array $array, string $category, array $newElement, int $position = 0)
{
if (array_key_exists($category, $array)) {
$categoryArray = $array[$category];
$categoryArray = arrayInsert($categoryArray, $position, $newElement);
$array[$category] = $categoryArray;
} else {
$array[$category] = $newElement;
}
return $array;
}
function arrayInsert($array, $position, $insertArray)
{
$ret = [];
if ($position == count($array)) {
$ret = $array $insertArray;
} else {
$i = 0;
foreach ($array as $key => $value) {
if ($position == $i ) {
$ret = $insertArray;
}
$ret[$key] = $value;
}
}
return $ret;
}
$newNavigation = category_add($navigation_array, 'CATEGORY_MAIN', ['Page2aaa' => "page2aaa.php"], 1);
echo '<pre>'; print_r($newNavigation);
// create whole new category
$newNavigation2 = category_add($navigation_array, 'CATEGORY_NEW2', ['new' => "new.php"]);
echo '<pre>'; print_r($newNavigation2);
CodePudding user response:
https://www.php.net/manual/en/function.array-splice.php#111204
When trying to splice an associative array into another,
array_splice
is missing two key ingredients:
- a string key for identifying the offset
- the ability to preserve keys in the replacement array
This is primarily useful when you want to replace an item in an array with another item, but want to maintain the ordering of the array without rebuilding the array one entry at a time.
<?php
function array_splice_assoc(&$input, $offset, $length, $replacement) {
$replacement = (array) $replacement;
$key_indices = array_flip(array_keys($input));
if (isset($input[$offset]) && is_string($offset)) {
$offset = $key_indices[$offset];
}
if (isset($input[$length]) && is_string($length)) {
$length = $key_indices[$length] - $offset;
}
$input = array_slice($input, 0, $offset, TRUE)
$replacement
array_slice($input, $offset $length, NULL, TRUE);
}
$fruit = array(
'orange' => 'orange',
'lemon' => 'yellow',
'lime' => 'green',
'grape' => 'purple',
'cherry' => 'red',
);
// Replace lemon and lime with apple
array_splice_assoc($fruit, 'lemon', 'grape', array('apple' => 'red'));
// Replace cherry with strawberry
array_splice_assoc($fruit, 'cherry', 1, array('strawberry' => 'red'));
?>