user1494286
user1494286

Reputation:

Move an element by key before another element by key in the context of an associative array

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

Answers (7)

The Coprolal
The Coprolal

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

luky
luky

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

Luca Reghellin
Luca Reghellin

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

ilias_gr
ilias_gr

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'];




I made a function for easy use:

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

Shehzad Bilal
Shehzad Bilal

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

Ry-
Ry-

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

Niet the Dark Absol
Niet the Dark Absol

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

Related Questions