Move one element before another in an associated array I have this task where I have an associated array in PHP and I want to manipulate the order of entries. Basically I want to be able to move entry Y before entry X.

So basically if I have the following array:

['foo1' =&gt; 'bar', 'foo2' =&gt; 'buzz', 'foo3' =&gt; 'bazz']


I want to be able to say: 'put element foo3 before foo2', resulting in the following:

['foo1' =&gt; 'bar', 'foo3' =&gt; 'bazz', 'foo2' =&gt; 'buzz']


I currently have the following code:

/**
 * Change the order of an associated array, moving by key before another
 *
 * @param array $arr
 * @param string $key
 * @param string $before
 * @return array
 */
public function moveKeyBefore(array $arr, string $key, string $before)
{
    $keys = array_keys($arr);
    if (in_array($key, $keys) &amp;&amp; in_array($before, $keys)) {
        $newArr = [];
        foreach ($arr as $idx =&gt; $value) {
            switch ($idx) {
                case $key :
                    continue;
                case $before:
                    $newArr[$key] = $arr[$key];
                    $newArr[$before] = $value;
                    break;
                default:
                    $newArr[$idx] = $value;
                    break;
            }
        }

        return $newArr;
    }

    return $arr;
}


This code basically works. However, I was wondering if there was an easier, less complex way of doing this.
I wouldn't bother with a foreach loop because it will do more iterating than necessary.  I recommend halving the array at the desired position and squeezing the element-to-be-moved into the gap created.  Consider this much more concise method:

Code: (Demo Link)

function moveKeyBefore($arr, $find, $move) {
    if (!isset($arr[$find], $arr[$move])) {
        return $arr;
    }

    $elem = [$move=&gt;$arr[$move]];  // cache the element to be moved
    $start = array_splice($arr, 0, array_search($find, array_keys($arr)));
    unset($start[$move]);  // only important if $move is in $start
    return $start + $elem + $arr;
}
$arr = ['foo1'=&gt;'bar', 'foo2'=&gt;'buzz', 'foo3'=&gt;'bazz'];
var_export(moveKeyBefore($arr, 'foo3', 'foo1'));


Output:

array (
  'foo2' =&gt; 'buzz',
  'foo1' =&gt; 'bar',
  'foo3' =&gt; 'bazz',
)


Explanation:

First check that both of the nominated keys exist in the array, if not return the input array untouched.  isset() is very fast, certainly faster than in_array().  Furthermore, the !isset() check will require both keys to exist otherwise the early return will be triggered.  This is as fast as this part gets.

Next, if both $find and $move exist in the array, my function will generate three array fragments:


$elem contains the associative array element declared by $move.
$start contains the elements that precede $find.  array_search() returns the offset (numeric key) of the $find value in $arr.
$arr is modified by array_splice() and contains all elements from find to the end.


After the splice, when $move is in the $arr half, the union action bumps the duplicate element out.  When $move is in the $start half, the convenient "bump" is lost, this means that the $move element needs to be removed from its original location.  unset() can be used unconditionally because it doesn't error when the target element is not found.