不改变顺序的情况下更改数组键

26

您可以通过设置新键并删除旧键来简单地更改数组元素的键:(在PHP中如何更改数组元素的键)

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

但这样会将键移动到数组的末尾。

是否有一些优雅的方法可以在不改变顺序的情况下更改键?

(PS:这个问题只是出于概念上的兴趣,不是因为我在其他地方需要它。)


我想用array_splice()和array_slice()这些不太好看的构造来完成这个技巧。 - Marc B
@MarcB,但是这种方法在使用字符串键时行不通。 - NikiC
1
@FelixDombek 我不确定我理解你的意思。$array[$oldKey] 只会返回键 $oldKey 对应的值。 - NikiC
1
@NikiC 这也是我想的,但如果它评估为5,那么unset()如何从数组中删除元素?PHP又如何知道应该从哪个数组中删除值5? - Felix Dombek
如果这是一个关联数组,你为什么关心“顺序”? - Mike Brant
显示剩余2条评论
8个回答

31

测试并且可行 :)

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

+1 虽然你可能应该为 $old_key 不在数组中的情况添加错误处理程序。 - Felix Kling
只有在键不存在时才替换第一个。添加一个if语句,就可以了;) - Kristian
2
将未更改的数组返回是否比抛出异常更好呢? - Ogier Schelvis

12

可能也可以试试这种方式:

$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));

输出:

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

8
我个人认为这个解决方案非常优雅!+1 - Luca Borrione
3
我也是。当使用Zend_Config_XML::toArray()时,这对于从XML标签名称中移除破折号/下划线非常有效。在我的情况下,数据是带有选项组的选择元素选项。我的optgroup名称是XML标记,并且标题中含有破折号。这对此很有效。 - axiom82
5
我不觉得这很优雅。非常危险。 - nawfal
1
这仅适用于示例数据是非常特定的情况。如果要替换的键存在于任何值中,则也将被替换。这不是一个安全的解决方案。 - Phil Hilton
1
@PhilHilton:我从未提到这是一种万能解决方案。这只是一个简便的解决方法。此外,在值中使用"EN":(引号字符串后跟冒号)非常罕见。 - anubhava

8

一种方法是使用foreach循环遍历数组并将其复制到新数组中,在迭代时有条件地更改键,例如,如果$key === 'foo',则不使用foo而使用bar:

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

另一种方法是对数组进行序列化,使用str_replace替换序列化的键,然后再将其反序列化回数组。虽然这并不是特别优雅的方法,并且可能出现错误,特别是当你不仅有标量值或多维数组时。
第三种方法 - 我最喜欢的方法 - 是你用 C 编写array_key_rename函数,并将其提议加入 PHP 核心 ;)

$newArray可以在foreach的作用域之外访问吗? - nawfal
@nawfal 是的,但是除非你分配返回值,否则不能在函数外部使用。 - Gordon
好的。从其他语言转到PHP有点奇怪 :) - nawfal

1
在继续之前,请检查键是否存在... 否则,如果新的键已经存在,结果可能是灾难性的...或者如果要替换的键不存在,则会造成不必要的处理时间/内存消耗。
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;
}

0

做一个双重翻转!至少这是我能想到的:

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

这只是理论,我还没有测试是否有效,但我想它应该是有效的。 - Tim Withers
6
如果存在重复的数值,那么这将失败。 - Felix Kling
1
如果值集合中存在重复,这将导致一些问题。 - Kemal Fadillah

0
我们正在使用此函数来更改数组中的多个键,同时保持顺序:
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));
}

您可以将数组作为$keys_map传递,如下所示:

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

这个解决方案基于 Kristian 的方案。


0
如果可能的话,在创建数组时也可以将更改键放在数组末尾:
$array=array('key1'=>'value1','key2'=>'value2','keytochange'=>'value');
$x=$array['keytochange'];
unset($array['keytochange']);
$array['newkey']=$x;

一个人还可以将许多键放在末尾进行更改,并为所有这些键执行此操作。 - abb

-2

你可以使用 array_combine函数。它可以将一个数组的键与另一个数组的值进行合并...

例如:

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

如果你有很多很多的键,只想改变其中一个怎么办?使用你的解决方案,你将被迫编写一个无尽的 $new_keys 数组。 - Luca Borrione

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接