Як в PHP ви змінюєте ключ елемента масиву?


348

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

Я не бачив функції, яка це робить, але я припускаю, що мені потрібно надати старий ключ і новий ключ (який я маю) і перетворити масив. Чи є ефективний спосіб зробити це?


Дивіться схожий stackoverflow.com/q/308703
Пітер Краус

Відповіді:


576
$arr[$newkey] = $arr[$oldkey];
unset($arr[$oldkey]);

5
Будьте обережні, що 1) Жодна з двох клавіш не має однакову для людської версії версії 2) Жодна версія, прочитана людиною, не має бути цифрами
Грег,

81
Також це, мабуть, змінить порядок масиву, до якого, можливо, вам потрібно буде обережно. Навіть асоціативні масиви в PHP впорядковані, а іноді цей порядок використовується за рахунок використання.
Робін Уінслоу

7
Так, чудово Робін. Чи є спосіб зберегти той самий порядок? Або вам потрібно створити новий масив, щоб досягти цього?
Саймон Іст

40
Питання про бонус: як змінити ідентифікатор, але зберегти порядок масиву?
Петро Пеллер

17
якщо значення ключа не змінюється, ви видалите елемент масиву. Ви можете перевірити це.
Піч

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

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

Це хороше рішення, якщо ваш масив має розумні розміри. Якщо ваш масив споживає більше половини доступної пам'яті PHP, це не працюватиме.
kingjeffrey

12
@kingjeffrey, не дуже. Значення масиву не буде дублюватися до тих пір, поки вони "просто скопійовані" без зміни. Наприклад, якщо є один масив, який містить 10'000 елементів і споживає 40 МБ пам'яті, при його копіюванні буде використано пам'ять, необхідну для зберігання 10000 лише посилань на вже наявні значення, а не на копії значень , тому, якщо 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;
}

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;   
}

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

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

Після успішного перейменування воно повернеться істинним , інакше помилковим .


Майте на увазі, що це змінює порядок масиву (елемент перейменованого ключа буде знаходитися в кінці масиву, а не в тому ж положенні в масиві, як він був раніше). Також я зазвичай не запускав ім'я функції з підкресленням (це традиційно використовується для позначення спеціальних функцій внутрішнього використання).
orrd

4

Легкі речі:

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

Ця функція збереже оригінальний порядок , але може бути проблематичною для дуже великих (наприклад, вище 10k записів) масивів щодо продуктивності та пам'яті .

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

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 ($ a)

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

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

найкращий спосіб - використання довідки, а не використання скидання (що робить ще один крок для очищення пам'яті)

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

рішення:

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

у вас є одна оригінальна і одна посилання з новим ім'ям.

або якщо ви не хочете мати два імені в одному значенні, добре зробити іншу вкладку та провести виступ за посиланням

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

Ви можете записати просту функцію, яка застосовує зворотний дзвінок до клавіш заданого масиву. Схожий на array_map

<?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 .


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;
}

Потім ви можете провести цикл і поміняти всі клавіші a на, наприклад, "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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.