Skip to content

Instantly share code, notes, and snippets.

@Alexander-Pop
Last active June 2, 2019 21:05
Show Gist options
  • Save Alexander-Pop/52dad0e9b2da0d642c8dac2da3112337 to your computer and use it in GitHub Desktop.
Save Alexander-Pop/52dad0e9b2da0d642c8dac2da3112337 to your computer and use it in GitHub Desktop.
PHP - Move one element before another in an associative array
<?php
function moveArrayKeyBefore($arr, $find, $move) {
if (!isset($arr[$find], $arr[$move])) {
return $arr;
}
$elem = [$move=>$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'=>'fooel1', 'foo2'=>'fooel2', 'foo3'=>'fooel1'];
var_export(moveArrayKeyBefore($arr, 'foo3', 'foo1'));
?>
Output:
array (
'foo2' => 'fooel2',
'foo1' => 'fooel1',
'foo3' => 'fooel3',
)
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.
https://codereview.stackexchange.com/questions/165263/move-one-element-before-another-in-an-associated-array
<?php
/*
Reorder a PHP array, moving items up or down
A quick set of functions to move items in a non-associative array
up or down by one, shifting the items around it appropriately.
Original usage was to for a set of UP and DOWN buttons to
manipulate the order of an array of items stored in Wordpress option.
*/
$a = array('a','b','c','d','e');
function down($a,$x) {
if( count($a)-1 > $x ) {
$b = array_slice($a,0,$x,true);
$b[] = $a[$x+1];
$b[] = $a[$x];
$b += array_slice($a,$x+2,count($a),true);
return($b);
} else { return $a; }
}
function up($a,$x) {
if( $x > 0 and $x < count($a) ) {
$b = array_slice($a,0,($x-1),true);
$b[] = $a[$x];
$b[] = $a[$x-1];
$b += array_slice($a,($x+1),count($a),true);
return($b);
} else { return $a; }
}
// Start
print_r($a);
/* Output
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
)
*/
// Move item 4 up
print_r(up($a,4));
/* Output
Array
(
[0] => a
[1] => b
[2] => c
[3] => e
[4] => d
)
*/
// Move item 0 down
print_r(down($a,0));
/* Output
Array
(
[0] => b
[1] => a
[2] => c
[3] => d
[4] => e
)
*/
// Test, move the bottom item down (ie. do nothing)
print_r(down($a,4));
/* Output
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
)
*/
// Test, move the top item up (ie. do nothing)
print_r(up($a,0));
/* Output
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
)
*/
Adding item to array or change existent item position after shifting elements up or down depending on available positions
<?php
/**
* Author:Wajdi Jurry <[email protected]> (https://github.com/wajdijurry)
* Gist: https://gist.github.com/wajdijurry/a00752123134342ccc9d13a480c9f013
*/
class ArrayManipulation
{
private $array;
public function __construct(array $array)
{
$this->array = $array;
}
/**
* Add/Change item position in array
* Shifting elements up/down depending on available positions
* Priority for shifting down
* @param int $position
* @param string $itemId
* @return array
*/
public function addItemChangePosition(int $position, string $itemId)
{
$max = 5; // Max number of elements in array
if ($position >= $max || $poition < 0) {
exit('Wrong Position');
}
// Remove item if exists
if (($key = array_search($itemId, $this->array)) !== false) {
unset($this->array[$key]);
}
$newArr = [];
if (array_key_exists($position, $this->array)) {
/**
* Determing shifting up or down
* Shifting up: 1, Shifting Down: -1
*/
$operator = (array_sum(array_keys($this->array)) >= array_sum(range($position, $max-1))) ? 1 : -1;
//Iterate over array, starting from $position till nonexistent element
for ($i = $position; $i >= $position * (-$operator); $i = $i - $operator) {
if (!array_key_exists($i, $this->array)) {
// Exit loop if element does not exist
break;
}
// Add items-to be shifted to $newArr
$newArr[$i - $operator] = $this->array[$i];
// Remove from original array (avoiding duplicate)
unset($this->array[$i]);
}
// Merging shifted elements with non-affected elements, keys preserved
$this->array = $newArr + array_diff($this->array, $newArr);
}
// Add new item to array
$this->array[$position] = $itemId;
// Sort array
ksort($this->array, SORT_NUMERIC);
return $this->array;
}
}
// Example 1:
$items = [
0 => 'item1',
1 => 'item2'
];
print_r($items = (new ArrayManipulation($items))->addItemChangePosition(1, 'new item')); // $items = [0 => 'item1', 1 => 'new item', 2 => 'item2']
// Example 2:
$items = [
0 => 'item1',
3 => 'item2'
];
print_r($items = (new ArrayManipulation($items))->addItemChangePosition(3, 'new item')); // $items = [0 => 'item1', 3 => 'new item', 4 => 'item2']
// Example 3:
$items = [
1 => 'item1',
2 => 'item2',
3 => 'item3',
4 => 'item4'
];
print_r($items = (new ArrayManipulation($items))->addItemChangePosition(4, 'new item')); // $items = [0 => 'item1', 1 => 'item2', 2 => 'item3', 3 => 'item4', 4 => 'new item']
// Example 3:
$items = [
1 => 'item1',
2 => 'item2',
3 => 'item3',
4 => 'item4'
];
print_r($items = (new ArrayManipulation($items, ))->addItemChangePosition(2, 'item4')); // $items = [1 => 'item1', 2 => 'item4', 3 => 'item2', 4 => 'item3']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment