I\'m looking for a simple function to move an array element to a new position in the array and resequence the indexes so that there are no gaps in the sequence. It doesnt ne
Take a look at this thread which describes a similar problem. The following solution is provided:
/**
* Move array element by index. Only works with zero-based,
* contiguously-indexed arrays
*
* @param array $array
* @param integer $from Use NULL when you want to move the last element
* @param integer $to New index for moved element. Use NULL to push
*
* @throws Exception
*
* @return array Newly re-ordered array
*/
function moveValueByIndex( array $array, $from=null, $to=null )
{
if ( null === $from )
{
$from = count( $array ) - 1;
}
if ( !isset( $array[$from] ) )
{
throw new Exception( "Offset $from does not exist" );
}
if ( array_keys( $array ) != range( 0, count( $array ) - 1 ) )
{
throw new Exception( "Invalid array keys" );
}
$value = $array[$from];
unset( $array[$from] );
if ( null === $to )
{
array_push( $array, $value );
} else {
$tail = array_splice( $array, $to );
array_push( $array, $value );
$array = array_merge( $array, $tail );
}
return $array;
}
The solution from hakre with two array_splice commands doesn't work with named arrays. The key of the moved element will be lost.
Instead you can splice the array two times and merge the parts.
function moveElement(&$array, $a, $b) {
$p1 = array_splice($array, $a, 1);
$p2 = array_splice($array, 0, $b);
$array = array_merge($p2,$p1,$array);
}
How does it work:
Example:
$fruits = array(
'bananas'=>'12',
'apples'=>'23',
'tomatoes'=>'21',
'nuts'=>'22',
'foo'=>'a',
'bar'=>'b'
);
moveElement($fruits, 1, 3);
// Result
['bananas'=>'12', 'tomatoes'=>'21', 'nuts'=>'22', 'apples'=>'23', 'foo'=>'a', 'bar'=>'b']
May be I'm wrong but shouldn't it be easier just to make a copy of the array and then replace the values?
function swap($input, $a, $b){
$output = $input;
$output[$a] = $input[$b];
$output[$b] = $input[$a];
return $output;
}
$array = ['a', 'c', 'b'];
$array = swap($array, 1, 2);
As commented, 2x array_splice
, there even is no need to renumber:
$array = [
0 => 'a',
1 => 'c',
2 => 'd',
3 => 'b',
4 => 'e',
];
function moveElement(&$array, $a, $b) {
$out = array_splice($array, $a, 1);
array_splice($array, $b, 0, $out);
}
moveElement($array, 3, 1);
Result:
[
0 => 'a',
1 => 'b',
2 => 'c',
3 => 'd',
4 => 'e',
];
A function that preserves keys:
function moveElementInArray($array, $toMove, $targetIndex) {
if (is_int($toMove)) {
$tmp = array_splice($array, $toMove, 1);
array_splice($array, $targetIndex, 0, $tmp);
$output = $array;
}
elseif (is_string($toMove)) {
$indexToMove = array_search($toMove, array_keys($array));
$itemToMove = $array[$toMove];
array_splice($array, $indexToMove, 1);
$i = 0;
$output = Array();
foreach($array as $key => $item) {
if ($i == $targetIndex) {
$output[$toMove] = $itemToMove;
}
$output[$key] = $item;
$i++;
}
}
return $output;
}
$arr1 = Array('a', 'b', 'c', 'd', 'e');
$arr2 = Array('A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e');
print_r(moveElementInArray($arr1, 3, 1));
print_r(moveElementInArray($arr2, 'D', 1));
Ouput:
Array
(
[0] => a
[1] => d
[2] => b
[3] => c
[4] => e
)
Array
(
[A] => a
[D] => d
[B] => b
[C] => c
[E] => e
)
A lot of good answers. Here's a simple one built on the answer by @RubbelDeCatc. The beauty of it is that you only need to know the array key, not its current position (before repositioning).
/**
* Reposition an array element by its key.
*
* @param array $array The array being reordered.
* @param string|int $key They key of the element you want to reposition.
* @param int $order The position in the array you want to move the element to. (0 is first)
*
* @throws \Exception
*/
function repositionArrayElement(array &$array, $key, int $order): void
{
if(($a = array_search($key, array_keys($array))) === false){
throw new \Exception("The {$key} cannot be found in the given array.");
}
$p1 = array_splice($array, $a, 1);
$p2 = array_splice($array, 0, $order);
$array = array_merge($p2, $p1, $array);
}
Straight forward to use:
$fruits = [
'bananas'=>'12',
'apples'=>'23',
'tomatoes'=>'21',
'nuts'=>'22',
'foo'=>'a',
'bar'=>'b'
];
repositionArrayElement($fruits, "foo", 1);
var_export($fruits);
/** Returns
array (
'bananas' => '12',
'foo' => 'a', <-- Now moved to position #1
'apples' => '23',
'tomatoes' => '21',
'nuts' => '22',
'bar' => 'b',
)
**/
Works on numeric arrays also:
$colours = ["green", "blue", "red"];
repositionArrayElement($colours, 2, 0);
var_export($colours);
/** Returns
array (
0 => 'red', <-- Now moved to position #0
1 => 'green',
2 => 'blue',
)
*/
Demo