0

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?

4
  • The expected outcome is to have ["test"] => Array ( ) at the second or second last position in the navigation_array. But instead I get [0] => Array ( ) Commented Jul 19, 2022 at 7:09
  • 1
    php.net/manual/en/function.array-splice.php: "Note: Keys in the replacement array are not preserved." Commented Jul 19, 2022 at 7:10
  • Dang, I knew it was something like that. But how does one work around that? I tried a combination of array_slice and array_merge, but to no avail. Commented Jul 19, 2022 at 7:13
  • @viamonster Please share a proper indented output. You can't throw some text and expect us to analyze it. Also, you still haven't made clear whether this output is for $MENU->category_add("test",2) or $MENU->category_add("test",-1) ? Commented Jul 19, 2022 at 7:45

2 Answers 2

1

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);
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I adapted your answer a bit to better integrate it in my code (as I e.g. already have a distinct function to add pages to a category), but it definitely set me on the right path.
1

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'));
?>

1 Comment

Thanks, this is an interesting function, but as far as I can see, it does replace stuff not insert it inbetween.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.