Reputation:
In PHP, I would like to have the ability to re-order an associative array by moving elements to certain positions in the array. Not necessary a sort, just a re-ordering of my choosing.
As an example, say I have an associative array as follows:
array(
'a' => 'Element A',
'b' => 'Element B',
'c' => 'Element C',
);
and in one case i may want to move C before B and have the following result:
array(
'a' => 'Element A',
'c' => 'Element C',
'b' => 'Element B',
);
or in another case i may want to move C before A and have the following result:
array(
'c' => 'Element C',
'a' => 'Element A',
'b' => 'Element B',
);
What I am trying to show, is simply a method for saying "Hey, I want to move this array element before this other array element" or "Hey, id like to move this array element to make sure that it comes after this other array element'
Upvotes: 15
Views: 12879
Reputation: 996
I like luky's answer the most but it requires specifying all of the keys. Most of the time you just want order a subset of the keys at the beginning of the array. This function will help then:
function reorder_assoc_array(
$cur, // current assoc array
$order // array conaining ordered (subset of) keys in $cur
) {
$result = [];
// first copy ordered key/values to result array
foreach($order as $key) {
$result[$key] = $cur[$key];
// unset key in original array
unset($cur[$key]);
}
// ... then copy all remaining keys that were not given in $order
foreach($cur as $key => $value) {
$result[$key] = $value;
}
return $result;
}
Example:
$assoc_arr = [
'b' => 'bbb',
'a' => 'aaa',
'c' => 'ccc',
'd' => 'ddd'
];
// suppose we want to swap the first two keys and leave the remaining keys as is
$assoc_arr = reorder_assoc_array($assoc_arr, ['a', 'b']);
// ... the order of keys is now a, b, c, d
Upvotes: 2
Reputation: 2370
i made a function based on one answer here. it takes the array of assoc array to be sorted, plus array of keys in which it should be resorted
// $data = array of assoc array
// $newKeysOrder = array("c","a","b");
function resort_assoc_array_by_keys($data, $newKeysOrder) {
foreach($data as $v) {
$out = [];
foreach($newKeysOrder as $k) {
$out[$k] = $v[$k];
}
$new[] = $out;
}
return $new;
}
Upvotes: 0
Reputation: 8113
A lot of difficult methods here :) In fact, you can exploit the preserve keys feature of array_slice()
.
$new_element = array('new_key' => 'value');
// if needed, find the insertion index by key
$index = array_search('key to search', array_keys($old_array));
// add element at index (note the last array_slice argument)
$new_array = array_slice($old_array, 0, $index+1, true) + $new_element + array_slice($old_array, $index+1, null, true);
Upvotes: 2
Reputation: 155
$arr = array(
'a' => 1,
'b' => 2,
'move me' => 9,
'c' => 3,
'd' => 4,
);
Hey, I want to move ['move me'] before ['b']. I can do it with only 4 lines of code!
$i = 0; foreach($arr as &$val) $val = array('sort' => (++$i * 10), 'val' => $val);
$arr['move me']['sort'] = $arr['b']['sort'] - 5;
uasort($arr, function($a, $b) { return $a['sort'] > $b['sort']; });
foreach($arr as &$val) $val = $val['val'];
function move_item(&$ref_arr, $key1, $move, $key2 = null)
{
$arr = $ref_arr;
if($key2 == null) $key2 = $key1;
if(!isset($arr[$key1]) || !isset($arr[$key2])) return false;
$i = 0; foreach($arr as &$val) $val = array('sort' => (++$i * 10), 'val' => $val);
if(is_numeric($move))
{
if($move == 0 && $key1 == $key2) return true;
elseif($move == 0) { $tmp = $arr[$key1]['sort']; $arr[$key1]['sort'] = $arr[$key2]['sort']; $arr[$key2]['sort'] = $tmp; }
else $arr[$key1]['sort'] = $arr[$key2]['sort'] + ($move * 10 + ($key1 == $key2 ? ($move < 0 ? -5 : 5) : 0));
}
else
{
switch($move)
{
case 'up': $arr[$key1]['sort'] = $arr[$key2]['sort'] - ($key1 == $key2 ? 15 : 5); break;
case 'down': $arr[$key1]['sort'] = $arr[$key2]['sort'] + ($key1 == $key2 ? 15 : 5); break;
case 'top': $arr[$key1]['sort'] = 5; break;
case 'bottom': $arr[$key1]['sort'] = $i * 10 + 5; break;
default: return false;
}
}
uasort($arr, function($a, $b) { return $a['sort'] > $b['sort']; });
foreach($arr as &$val) $val = $val['val'];
$ref_arr = $arr;
return true;
}
Examples:
move_item($arr, 'move me', 'up'); //move it one up
move_item($arr, 'move me', 'down'); //move it one down
move_item($arr, 'move me', 'top'); //move it to top
move_item($arr, 'move me', 'bottom'); //move it to bottom
move_item($arr, 'move me', -1); //move it one up
move_item($arr, 'move me', 1); //move it one down
move_item($arr, 'move me', 2); //move it two down
move_item($arr, 'move me', 'up', 'b'); //move it before ['b']
move_item($arr, 'move me', -1, 'b'); //move it before ['b']
move_item($arr, 'move me', 'down', 'b'); //move it after ['b']
move_item($arr, 'move me', 1, 'b'); //move it after ['b']
move_item($arr, 'move me', 2, 'b'); //move it two positions after ['b']
//Special syntax, to swap two elements:
move_item($arr, 'a', 0, 'd'); //Swap ['a'] with ['d']
I hope this helps a lot of people, because it is an awesome function! :D
Upvotes: 13
Reputation: 2523
If you mean to swap two values you could make a function like this:
function array_swap($key1, $key2, $array) {
$newArray = array ();
foreach ($array as $key => $value) {
if ($key == $key1) {
$newArray[$key2] = $array[$key2];
} elseif ($key == $key2) {
$newArray[$key1] = $array[$key1];
} else {
$newArray[$key] = $value;
}
}
return $newArray;
}
Upvotes: 2
Reputation: 225044
array_splice
unfortunately doesn't work with associative arrays, so here's something a little messier:
$keys = array_keys($arr);
$values = array_values($arr);
$keyIndex = array_search($someKey, $keys);
array_splice($keys, $keyIndex, 1);
array_splice($values, $keyIndex, 1);
$insertIndex = 1;
array_splice($keys, $insertIndex, 0, array($someKey));
array_splice($values, $insertIndex, 0, array($arr[$someKey]));
$arr = array_combine($keys, $values);
Upvotes: 0
Reputation: 324750
For a custom sorting, you can for example create an array that is the desired order of the keys and then associate the values with them. Example:
$input = array("a"=>"Element A","b"=>"Element B","c"=>"Element C");
$order = array("c","a","b");
$out = array();
foreach($order as $k) {
$out[$k] = $input[$k];
}
The elements in $out
will be in the order specified.
Upvotes: 11