26

You can "change" the key of an array element simply by setting the new key and removing the old:

$array[$newKey] = $array[$oldKey];
unset($array[$oldKey]);

But this will move the key to the end of the array.

Is there some elegant way to change the key without changing the order?

(PS: This question is just out of conceptual interest, not because I need it anywhere.)

7
  • I'd imagine some ugly construct with array_splice() and array_slice() would do the trick Commented Jan 16, 2012 at 17:49
  • @MarcB That wouldn't work with string keys though. Commented Jan 16, 2012 at 17:51
  • I'm not a PHP programmer, but what in the world are the semantics of $arr[$oldKey] if this works as an argument to a function which removes $oldKey from $arr? I think PHP might be more interesting than I previously thought, will have to look into this … Commented Jan 16, 2012 at 19:53
  • 1
    @FelixDombek I'm not sure I get you. $array[$oldKey] will just return the value with the key $oldKey. Commented Jan 16, 2012 at 20:00
  • 1
    @NikiC That's what I also thought, but if it evaluates to, say, 5, then how does unset() delete the element from the array? How does PHP even know in which array it should delete the value 5? Commented Jan 16, 2012 at 20:04

8 Answers 8

32

Tested and works :)

function replace_key($array, $old_key, $new_key) {
    $keys = array_keys($array);
    if (false === $index = array_search($old_key, $keys, true)) {
        throw new Exception(sprintf('Key "%s" does not exist', $old_key));
    }
    $keys[$index] = $new_key;
    return array_combine($keys, array_values($array));
}

$array = [ 'a' => '1', 'b' => '2', 'c' => '3' ];    
$new_array = replace_key($array, 'b', 'e');
Sign up to request clarification or add additional context in comments.

3 Comments

+1 Though you probably should add an error handler for the case that $old_key is not in the array.
Only if the key doesn't exist then replace the first one. Add an if clause, and youre ok;)
Wouldn't one be better off returning the unchanged array instead of throwing an exception?
12

Something like this may also work:

$langs = array("EN" => "English", 
        "ZH" => "Chinese", 
        "DA" => "Danish",
        "NL" => "Dutch", 
        "FI" => "Finnish", 
        "FR" => "French",
        "DE" => "German");
$json = str_replace('"EN":', '"en":', json_encode($langs));
print_r(json_decode($json, true));

OUTPUT:

Array
(
    [en] => English
    [ZH] => Chinese
    [DA] => Danish
    [NL] => Dutch
    [FI] => Finnish
    [FR] => French
    [DE] => German
)

5 Comments

I personally find this solution very elegant! +1
Me too. This works wonderful for removing dashes/underscores from XML tag names when using Zend_Config_XML::toArray(). In my case, the data is options for select elements w/ optgroups. My optgroup names were XML tags, and the titles had dashes. This worked well for that.
I dont find this elegant. Very dangerous.
This only works because the example data is a very specific case. If the key to be replaced exists as any value then that would also be replaced. This is not a safe solution.
@PhilHilton: No where I mentioned this to be a panacea kind of solution. This is just a shorthand work around. Moreover having "EN": (quoted string followed by colon) in value is very rare.
8

One way would be to simply use a foreach iterating over the array and copying it to a new array, changing the key conditionally while iterating, e.g. if $key === 'foo' then dont use foo but bar:

function array_key_rename($array, $oldKey, $newKey) 
{
    $newArray = [];
    foreach ($array as $key => $value) {
        $newArray[$key === $oldKey ? $newKey : $key] = $value;
    }
    return $newArray;
}

Another way would be to serialize the array, str_replace the serialized key and then unserialize back into an array again. That isnt particular elegant though and likely error prone, especially when you dont only have scalars or multidimensional arrays.

A third way - my favorite - would be you writing array_key_rename in C and proposing it for the PHP core ;)

3 Comments

Is $newArray accessible from outside the scope of foreach?
@nawfal yes, but not outside the function unless you assign the return value
OK. Bit strange to get used to PHP coming from another language :)
1

Check keys existence before proceeding… Otherwise the result can be catastrophic if the new key already exists... or unnecessary processing time/memory consumption if the key to be replaced does not exist.

function array_rename_key( array $array, $old_key, $new_key ) {
    // if $new_key already exists, or if $old_key doesn't exists
    if ( array_key_exists( $new_key, $array ) || ! array_key_exists( $old_key, $array ) ) {
        return $array;
    }

    $new_array = [];
    foreach ( $array as $k => $v ) {
        $new_array[ $k === $old_key ? $new_key : $k ] = $v;
    }

    return $new_array;
}

Comments

0

Do a double flip! At least that is all I can think of:

$array=("foo"=>"bar","asdf"=>"fdsa");
$array=array_flip($array);
$array["bar"]=>'newkey';
$array=array_flip($array);

3 Comments

And this is just theory, I haven't tested to see if it works, but I imagine it would.
That will fail if the there are duplicate values.
This will cause some problems if the there are duplicates in the value sets
0

We are using this function for changing multiple array keys within an array keeping the order:

function replace_keys($array, $keys_map) {
    $keys = array_keys($array);
    foreach($keys_map as $old_key=>$new_key){
        if (false === $index = array_search($old_key, $keys)) {
            continue;
        }
        $keys[$index] = $new_key;
    }
    return array_combine($keys, array_values($array));
}

You can pass an array as $keys_map, like this:

$keys_map=array("old_key_1"=>"new_key_1", "old_key_2"=>"new_key_2",...)

This solution is based on Kristian one.

Comments

0

If possible, one can also put the key to change at the end of the array in the moment of creation :

$array=array('key1'=>'value1','key2'=>'value2','keytochange'=>'value');
$x=$array['keytochange'];
unset($array['keytochange']);
$array['newkey']=$x;

1 Comment

One can also put many keys to change at the end and do it for all these keys
-2

You could use array_combine. It merges an array for keys and another for values...

For instance:

$original_array =('foo'=>'bar','asdf'=>'fdsa');
$new_keys       = array('abc', 'def');
$new_array      = array_combine($new_keys, $original_array);

1 Comment

what if you have many many keys and want to change just one? With your solution you would be obliged to write an endless $new_keys array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.