В PHP, как вы меняете ключ элемента массива?

348

У меня есть ассоциативный массив в виде key => value где ключ является числовым значением, однако это не последовательное числовое значение. Ключ на самом деле является идентификационным номером, а значение - счетчиком. Это нормально для большинства случаев, однако я хочу функцию, которая получает удобочитаемое имя массива и использует его для ключа без изменения значения.

Я не видел функцию, которая делает это, но я предполагаю, что мне нужно предоставить старый ключ и новый ключ (оба из которых у меня есть) и преобразовать массив. Есть ли эффективный способ сделать это?

Томас Оуэнс
источник
Посмотреть похожий stackoverflow.com/q/308703
Питер Краусс

Ответы:

578
$arr[$newkey] = $arr[$oldkey];
unset($arr[$oldkey]);
KernelM
источник
5
Только будьте осторожны, что 1) Нет двух ключей, имеющих одинаковую читабельную версию 2) Никаких читаемых человеком версий не бывает цифрами
Грег
81
Также это, вероятно, изменит порядок массива, о котором вам, возможно, следует быть осторожным. Даже ассоциативные массивы в PHP упорядочены, и иногда этот порядок используется.
Робин Уинслоу
7
Да, замечательно, Робин. Есть ли способ сохранить тот же порядок? Или вам нужно создать новый массив для этого?
Саймон Ист
40
Бонусный вопрос: как изменить идентификатор, но сохранить порядок массива?
Петр Пеллер
17
если значение ключа не меняется, вы удалите элемент массива. Вы можете проверить это.
Peeech
97

Чтобы сделать это и сохранить порядок массива, нужно поместить ключи массива в отдельный массив, найти и заменить ключ в этом массиве, а затем объединить его обратно со значениями.

Вот функция, которая делает именно это:

function change_key( $array, $old_key, $new_key ) {

    if( ! array_key_exists( $old_key, $array ) )
        return $array;

    $keys = array_keys( $array );
    $keys[ array_search( $old_key, $keys ) ] = $new_key;

    return array_combine( $keys, $array );
}
DiverseAndRemote.com
источник
2
Спасибо, это было действительно полезно, так как мне нужно было сохранить порядок массива. Я уже попробовал принятый ответ, прежде чем нашел эту страницу.
Gillytech
3
Да очень предпочитаю сохранить порядок массива, выглядит аккуратнее.
Фил Кук
2
Пришлось сохранить ключевой порядок, хороший, работал как шарм!
Учащийся
Имейте в виду, если вы хотите спектакли или сохранение заказа: stackoverflow.com/a/58619985/1617857
Léo Benoist
54

если ваш arrayпостроен из запроса к базе данных, вы можете изменить ключ непосредственно из mysqlоператора:

вместо того

"select ´id´ from ´tablename´..."

использовать что-то вроде:

"select ´id´ **as NEWNAME** from ´tablename´..."
Саймон Франко
источник
отличный ответ, очень ценный!
DevMoutarde
20

Ответ от KernelM хорош, но во избежание проблемы, поднятой Грегом в комментарии (конфликтующие ключи), было бы безопаснее использовать новый массив

$newarr[$newkey] = $oldarr[$oldkey];
$oldarr=$newarr;
unset($newarr);
KJG
источник
Это хорошее решение, если ваш массив имеет разумный размер. Если ваш массив потребляет более половины доступной памяти PHP, это не будет работать.
Кингжеффри
12
@kingjeffrey, не совсем. Значения массива не будут дублироваться, пока они «просто скопированы» без изменения. Например, если есть один массив, который содержит 10 000 элементов и использует 40 МБ памяти, его копирование будет занимать память, необходимую для хранения 10 000 ссылок только на уже существующие значения, а не на копии значений , поэтому, если 1 массив использует 40 МБ, его копия может потреблять, может быть, 0,5 МБ (проверено).
binaryLV
17

Вы можете использовать второй ассоциативный массив, который отображает понятные человеку имена на идентификаторы. Это также обеспечило бы отношение «многие к 1». Затем сделайте что-то вроде этого:

echo 'Widgets: ' . $data[$humanreadbleMapping['Widgets']];
Том Риттер
источник
11

Если вы также хотите, чтобы позиция нового ключа массива была такой же, как и у старого, вы можете сделать это:

function change_array_key( $array, $old_key, $new_key) {
    if(!is_array($array)){ print 'You must enter a array as a haystack!'; exit; }
    if(!array_key_exists($old_key, $array)){
        return $array;
    }

    $key_pos = array_search($old_key, array_keys($array));
    $arr_before = array_slice($array, 0, $key_pos);
    $arr_after = array_slice($array, $key_pos + 1);
    $arr_renamed = array($new_key => $array[$old_key]);

    return $arr_before + $arr_renamed + $arr_after;
}
spreadzz
источник
7

Если ваш массив рекурсивный, вы можете использовать эту функцию: протестируйте эти данные:

    $datos = array
    (
        '0' => array
            (
                'no' => 1,
                'id_maquina' => 1,
                'id_transaccion' => 1276316093,
                'ultimo_cambio' => 'asdfsaf',
                'fecha_ultimo_mantenimiento' => 1275804000,
                'mecanico_ultimo_mantenimiento' =>'asdfas',
                'fecha_ultima_reparacion' => 1275804000,
                'mecanico_ultima_reparacion' => 'sadfasf',
                'fecha_siguiente_mantenimiento' => 1275804000,
                'fecha_ultima_falla' => 0,
                'total_fallas' => 0,
            ),

        '1' => array
            (
                'no' => 2,
                'id_maquina' => 2,
                'id_transaccion' => 1276494575,
                'ultimo_cambio' => 'xx',
                'fecha_ultimo_mantenimiento' => 1275372000,
                'mecanico_ultimo_mantenimiento' => 'xx',
                'fecha_ultima_reparacion' => 1275458400,
                'mecanico_ultima_reparacion' => 'xx',
                'fecha_siguiente_mantenimiento' => 1275372000,
                'fecha_ultima_falla' => 0,
                'total_fallas' => 0,
            )
    );

вот функция:

function changekeyname($array, $newkey, $oldkey)
{
   foreach ($array as $key => $value) 
   {
      if (is_array($value))
         $array[$key] = changekeyname($value,$newkey,$oldkey);
      else
        {
             $array[$newkey] =  $array[$oldkey];    
        }

   }
   unset($array[$oldkey]);          
   return $array;   
}
pajafumo
источник
7
$array = [
    'old1' => 1
    'old2' => 2
];

$renameMap = [
    'old1' => 'new1',   
    'old2' => 'new2'
];

$array = array_combine(array_map(function($el) use ($renameMap) {
    return $renameMap[$el];
}, array_keys($array)), array_values($array));

/*
$array = [
    'new1' => 1
    'new2' => 2
];
*/
Темури
источник
3
Я люблю меня, мои функции массива. Я собирался предложить это как хорошую однострочную строку для переименования всех ключей и поддержания порядка массива, но я рекомендую ваш вместо этого.
Осень Леонард
6

Мне нравится решение KernelM, но мне нужно что-то, что могло бы справиться с потенциальными конфликтами ключей (где новый ключ может соответствовать существующему ключу). Вот что я придумал:

function swapKeys( &$arr, $origKey, $newKey, &$pendingKeys ) {
    if( !isset( $arr[$newKey] ) ) {
        $arr[$newKey] = $arr[$origKey];
        unset( $arr[$origKey] );
        if( isset( $pendingKeys[$origKey] ) ) {
            // recursion to handle conflicting keys with conflicting keys
            swapKeys( $arr, $pendingKeys[$origKey], $origKey, $pendingKeys );
            unset( $pendingKeys[$origKey] );
        }
    } elseif( $newKey != $origKey ) {
        $pendingKeys[$newKey] = $origKey;
    }
}

Затем вы можете циклически перебирать массив следующим образом:

$myArray = array( '1970-01-01 00:00:01', '1970-01-01 00:01:00' );
$pendingKeys = array();
foreach( $myArray as $key => $myArrayValue ) {
    // NOTE: strtotime( '1970-01-01 00:00:01' ) = 1 (a conflicting key)
    $timestamp = strtotime( $myArrayValue );
    swapKeys( $myArray, $key, $timestamp, $pendingKeys );
}
// RESULT: $myArray == array( 1=>'1970-01-01 00:00:01', 60=>'1970-01-01 00:01:00' )
kingjeffrey
источник
6

Вот вспомогательная функция для достижения этой цели:

/**
 * Helper function to rename array keys.
 */
function _rename_arr_key($oldkey, $newkey, array &$arr) {
    if (array_key_exists($oldkey, $arr)) {
        $arr[$newkey] = $arr[$oldkey];
        unset($arr[$oldkey]);
        return TRUE;
    } else {
        return FALSE;
    }
}

довольно основанный на ответе @KernelM .

Использование:

_rename_arr_key('oldkey', 'newkey', $my_array);

Он вернет true при успешном переименовании, иначе false .

kenorb
источник
Имейте в виду, что это меняет порядок массива (элемент переименованного ключа будет находиться в конце массива, а не в той же позиции в массиве, в которой он был изначально). Также я бы обычно не начинал имя функции с подчеркивания (это традиционно используется для обозначения специальных функций внутреннего использования).
orrd
4

Легкие вещи:

эта функция будет принимать целевой $ hash, а $ replacements также является хешем, содержащим ассоциации newkey => oldkey .

Эта функция сохранит исходный порядок , но может быть проблематичной для очень больших (например, более 10 тыс. Записей) массивов, касающихся производительности и памяти .

function keyRename(array $hash, array $replacements) {
    $new=array();
    foreach($hash as $k=>$v)
    {
        if($ok=array_search($k,$replacements))
            $k=$ok;
        $new[$k]=$v;
    }
    return $new;    
}

эта альтернативная функция сделала бы то же самое, с гораздо лучшей производительностью и использованием памяти, за счет потери исходного порядка (что не должно быть проблемой, так как она хеш-таблица!)

function keyRename(array $hash, array $replacements) {

    foreach($hash as $k=>$v)
        if($ok=array_search($k,$replacements))
        {
          $hash[$ok]=$v;
          unset($hash[$k]);
        }

    return $hash;       
}
надир
источник
4

этот код поможет заменить старый ключ на новый

$i = 0;
$keys_array=array("0"=>"one","1"=>"two");

$keys = array_keys($keys_array);

for($i=0;$i<count($keys);$i++) {
    $keys_array[$keys_array[$i]]=$keys_array[$i];
    unset($keys_array[$i]);
}
print_r($keys_array);

показывать как

$keys_array=array("one"=>"one","two"=>"two");
Картикеян Ганесан
источник
3

Простое сравнение производительности обоих решений.

Решение 1 Скопируйте и удалите (заказ потерян) https://stackoverflow.com/a/240676/1617857

for ($i =0; $i < 100000000; $i++){
    $array = ['test' => 'value'];
    $array['test2'] = $array['test'];
    unset($array['test']);
}

Решение 2 Переименуйте ключ https://stackoverflow.com/a/21299719/1617857

for ($i =0; $i < 100000000; $i++){
    $array = ['test' => 'value'];
    $keys = array_keys( $array );
    $keys[array_search('test', $keys, true)] = 'test2';
    array_combine( $keys, $array );
}

Полученные результаты:

php solution1.php  6.33s  user 0.02s system 99% cpu 6.356  total
php solution1.php  6.37s  user 0.01s system 99% cpu 6.390  total
php solution2.php  12.14s user 0.01s system 99% cpu 12.164 total
php solution2.php  12.57s user 0.03s system 99% cpu 12.612 total
Лео Бенуа
источник
2

Вы можете использовать эту функцию на основе array_walk:

function mapToIDs($array, $id_field_name = 'id')
{
    $result = [];
    array_walk($array, 
        function(&$value, $key) use (&$result, $id_field_name)
        {
            $result[$value[$id_field_name]] = $value;
        }
    );
    return $result;
}

$arr = [0 => ['id' => 'one', 'fruit' => 'apple'], 1 => ['id' => 'two', 'fruit' => 'banana']];
print_r($arr);
print_r(mapToIDs($arr));

Это дает:

Array(
    [0] => Array(
        [id] => one
        [fruit] => apple
    )
    [1] => Array(
        [id] => two
        [fruit] => banana
    )
)

Array(
    [one] => Array(
        [id] => one
        [fruit] => apple
    )
    [two] => Array(
        [id] => two
        [fruit] => banana
    )
)
Alekzander
источник
1

это работает для переименования первого ключа:

$a = ['catine' => 'cat', 'canine'  => 'dog'];
$tmpa['feline'] = $a['catine'];
unset($a['catine']);
$a = $tmpa + $a;

затем print_r ($ a) отображает восстановленный массив в порядке:

Array
(
    [feline] => cat
    [canine] => dog
)

это работает для переименования произвольного ключа:

$a = ['canine'  => 'dog', 'catine' => 'cat', 'porcine' => 'pig']
$af = array_flip($a)
$af['cat'] = 'feline';
$a = array_flip($af)

print_r ($ а)

Array
(
    [canine] => dog
    [feline] => cat
    [porcine] => pig
)

обобщенная функция:

function renameKey($oldkey, $newkey, $array) {
    $val = $array[$oldkey];
    $tmp_A = array_flip($array);
    $tmp_A[$val] = $newkey;

    return array_flip($tmp_A);
}
wmmso
источник
1

Если вы хотите заменить несколько ключей одновременно (сохраняя порядок):

/**
 * Rename keys of an array
 * @param array $array (asoc)
 * @param array $replacement_keys (indexed)
 * @return array
 */
function rename_keys($array, $replacement_keys)  {
      return array_combine($replacement_keys, array_values($array));
}

Использование:

$myarr = array("a" => 22, "b" => 144, "c" => 43);
$newkeys = array("x","y","z");
print_r(rename_keys($myarr, $newkeys));
//must return: array("x" => 22, "y" => 144, "z" => 43);
Лепе
источник
1

Существует альтернативный способ изменить ключ элемента массива при работе с полным массивом - без изменения порядка массива. Это просто скопировать массив в новый массив.

Например, я работал со смешанным многомерным массивом, который содержал индексированные и ассоциативные ключи - и я хотел заменить целочисленные ключи их значениями, не нарушая порядок.

Я сделал это, переключив ключ / значение для всех записей числового массива - здесь: ['0' => 'foo']. Обратите внимание, что заказ не поврежден.

<?php
$arr = [
    'foo',
    'bar'=>'alfa',
    'baz'=>['a'=>'hello', 'b'=>'world'],
];

foreach($arr as $k=>$v) {
    $kk = is_numeric($k) ? $v : $k;
    $vv = is_numeric($k) ? null : $v;
    $arr2[$kk] = $vv;
}

print_r($arr2);

Вывод:

Array (
    [foo] => 
    [bar] => alfa
    [baz] => Array (
            [a] => hello
            [b] => world
        )
)
Кристоффер Боман
источник
1

лучший способ - использовать ссылку, а не использовать unset (что делает еще один шаг для очистки памяти)

$tab = ['two' => [] ];

решение:

$tab['newname'] = & $tab['two'];

у вас есть один оригинал и одна ссылка с новым именем.

или, если вы не хотите иметь два имени в одном значении, хорошо сделать другую вкладку и foreach по ссылке

foreach($tab as $key=> & $value) {
    if($key=='two') { 
        $newtab["newname"] = & $tab[$key];
     } else {
        $newtab[$key] = & $tab[$key];
     }
}

Итерация лучше для ключей, чем клонирование всего массива, и очистка старого массива, если у вас длинные данные, такие как 100 строк +++ и т. Д.

Камиль Домбровски
источник
0

Хм, я не тестировал раньше, но я думаю, что этот код работает

function replace_array_key($data) {
    $mapping = [
        'old_key_1' => 'new_key_1',
        'old_key_2' => 'new_key_2',
    ];

    $data = json_encode($data);
    foreach ($mapping as $needed => $replace) {
        $data = str_replace('"'.$needed.'":', '"'.$replace.'":', $data);
    }

    return json_decode($data, true);
}
Франк Ву
источник
JSON кодировать и декодировать? Это действительно плохой ответ.
kixorz
0

Тот, который сохраняет порядок, который прост для понимания:

function rename_array_key(array $array, $old_key, $new_key) {
  if (!array_key_exists($old_key, $array)) {
      return $array;
  }
  $new_array = [];
  foreach ($array as $key => $value) {
    $new_key = $old_key === $key
      ? $new_key
      : $key;
    $new_array[$new_key] = $value;
  }
  return $new_array;
}
Андрей
источник
0

Вы можете написать простую функцию, которая применяет обратный вызов к ключам данного массива. Похож на массив

<?php
function array_map_keys(callable $callback, array $array) {
    return array_merge([], ...array_map(
        function ($key, $value) use ($callback) { return [$callback($key) => $value]; },
        array_keys($array),
        $array
    ));
}

$array = ['a' => 1, 'b' => 'test', 'c' => ['x' => 1, 'y' => 2]];
$newArray = array_map_keys(function($key) { return 'new' . ucfirst($key); }, $array);

echo json_encode($array); // {"a":1,"b":"test","c":{"x":1,"y":2}}
echo json_encode($newArray); // {"newA":1,"newB":"test","newC":{"x":1,"y":2}}

Вот суть https://gist.github.com/vardius/650367e15abfb58bcd72ca47eff096ca#file-array_map_keys-php .

vardius
источник
0

Эта функция переименует ключ массива, сохраняя его позицию, в сочетании с поиском по индексу.

function renameArrKey($arr, $oldKey, $newKey){
    if(!isset($arr[$oldKey])) return $arr; // Failsafe
    $keys = array_keys($arr);
    $keys[array_search($oldKey, $keys)] = $newKey;
    $newArr = array_combine($keys, $arr);
    return $newArr;
}

Использование:

$arr = renameArrKey($arr, 'old_key', 'new_key');
Грант
источник
-1

Эта базовая функция обрабатывает замену ключей массива и поддерживает массив в исходном порядке ...

public function keySwap(array $resource, array $keys)
{
    $newResource = [];

    foreach($resource as $k => $r){
        if(array_key_exists($k,$keys)){
            $newResource[$keys[$k]] = $r;
        }else{
            $newResource[$k] = $r;
        }
    }

    return $newResource;
}

Затем вы можете перебрать и поменять местами все клавиши «а» с «z», например ...

$inputs = [
  0 => ['a'=>'1','b'=>'2'],
  1 => ['a'=>'3','b'=>'4']
]

$keySwap = ['a'=>'z'];

foreach($inputs as $k=>$i){
    $inputs[$k] = $this->keySwap($i,$keySwap);
}
MikeyJ
источник