In PHP, come si modifica la chiave di un elemento array?


348

Ho un array associativo nella forma in key => valuecui la chiave è un valore numerico, tuttavia non è un valore numerico sequenziale. La chiave è in realtà un numero ID e il valore è un conteggio. Questo va bene per la maggior parte dei casi, tuttavia voglio una funzione che ottenga il nome leggibile dall'array dell'array e lo usi per la chiave, senza cambiare il valore.

Non ho visto una funzione che fa questo, ma presumo che debba fornire la vecchia chiave e la nuova chiave (entrambe le quali ho) e trasformare l'array. Esiste un modo efficace per farlo?


Risposte:


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

5
Fai solo attenzione che 1) Non ci siano due chiavi con la stessa versione leggibile dall'uomo 2) Nessuna versione leggibile dall'uomo può essere un numero
Greg,

81
Anche questo presumibilmente cambierebbe l'ordine dell'array, di cui potresti aver bisogno di fare attenzione. Anche le matrici associative in PHP sono ordinate, e talvolta quell'ordine viene sfruttato.
Robin Winslow,

7
Sì, ottimo punto Robin. C'è un modo per mantenere lo stesso ordine? O hai bisogno di creare un nuovo array per farlo?
Simon East,

40
Domanda bonus: come modificare l'ID, ma preservare l'ordine dell'array?
Petr Peller,

17
se il valore della chiave non cambia, eliminerai un elemento array. Potresti voler verificarlo.
Peeech,

97

Il modo in cui lo faresti e preserveresti l'ordinamento dell'array è mettendo le chiavi dell'array in un array separato, trova e sostituisci la chiave in quell'array e poi combinala di nuovo con i valori.

Ecco una funzione che fa proprio questo:

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
Grazie, è stato davvero utile in quanto avevo bisogno di preservare l'ordine dell'array. Avevo già provato la risposta accettata prima di trovare questa pagina.
Gillytech,

3
Sì, molto preferisco preservare l'ordine dell'array, sembra più ordinato.
Phil Cook,

2
Ho dovuto preservare l'ordine delle chiavi, buono, ha funzionato come un incantesimo!
Principiante

Pensa se vuoi esibizioni o conservazione degli ordini: stackoverflow.com/a/58619985/1617857
Léo Benoist,

54

se il tuo arrayè costruito da una query del database, puoi cambiare la chiave direttamente mysqldall'istruzione:

invece di

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

usa qualcosa come:

"select ´id´ **as NEWNAME** from ´tablename´..."

ottima risposta, molto preziosa!
DevMoutarde,

20

La risposta di KernelM è buona, ma per evitare il problema sollevato da Greg nel commento (chiavi in ​​conflitto), usare un nuovo array sarebbe più sicuro

$newarr[$newkey] = $oldarr[$oldkey];
$oldarr=$newarr;
unset($newarr);

Questa è una buona soluzione, purché l'array abbia dimensioni ragionevoli. Se l'array consuma più della metà della memoria PHP disponibile, questo non funzionerà.
Kingjeffrey,

12
@kingjeffrey, non proprio. I valori dell'array non saranno duplicati finché saranno "appena copiati" senza essere modificati. Ad esempio, se esiste un array che contiene 10'000 elementi e consuma 40 MB di memoria, copiandolo si consuma la memoria necessaria per archiviare 10'000 solo riferimenti a valori già esistenti anziché copie di valori , quindi se 1 array consuma 40 MB, la sua copia potrebbe consumare forse 0,5 MB (testato).
binaryLV

17

È possibile utilizzare un secondo array associativo che associa nomi leggibili umani all'ID. Ciò fornirebbe anche una relazione Many to 1. Quindi fai qualcosa del genere:

echo 'Widgets: ' . $data[$humanreadbleMapping['Widgets']];

11

Se vuoi che anche la posizione della nuova chiave dell'array sia la stessa di quella precedente, puoi farlo:

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

Se l'array è ricorsivo, è possibile utilizzare questa funzione: testare questi dati:

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

ecco la funzione:

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
Mi piacciono le mie funzioni di array. Stavo per suggerire questo come un buon one-liner per rinominare tutte le chiavi e mantenere l'ordine dell'array, ma raccomanderò invece il tuo.
Autunno Leonard,

6

Mi piace la soluzione di KernelM, ma avevo bisogno di qualcosa che potesse gestire potenziali conflitti di chiavi (dove una nuova chiave potrebbe corrispondere a una chiave esistente). Ecco cosa mi è venuto in mente:

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

È quindi possibile scorrere un array come questo:

$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

Ecco una funzione di aiuto per raggiungere questo obiettivo:

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

piuttosto basato sulla risposta @KernelM .

Uso:

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

Restituirà vero in caso di rinomina riuscita, altrimenti falso .


Tenere presente che ciò modifica l'ordine dell'array (l'elemento della chiave rinominata si troverà alla fine dell'array, non nella stessa posizione dell'array originale). Inoltre, di solito non inizierei un nome di funzione con un carattere di sottolineatura (che è tradizionalmente usato per designare speciali funzioni di uso interno).
or

4

Cose facili:

questa funzione accetta l'obiettivo $ hash e $ sostituzioni è anche un hash contenente associazioni newkey => oldkey .

Questa funzione lo farà ordine originale , ma potrebbe essere problematica per array molto grandi (come sopra i record di 10k) relativi a prestazioni e memoria .

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

questa funzione alternativa farebbe lo stesso, con prestazioni e utilizzo della memoria di gran lunga migliori , al costo di perdere l'ordine originale (che non dovrebbe essere un problema poiché è hashtable!)

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

questo codice aiuterà a cambiare il vecchio in uno nuovo

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

mostra come

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

3

Semplice confronto comparativo di entrambe le soluzioni.

Soluzione 1 Copia e rimuovi (ordine perso) https://stackoverflow.com/a/240676/1617857

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

Soluzione 2 Rinominare la chiave 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 );
}

risultati:

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

È possibile utilizzare questa funzione in base a 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));

Dà:

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

questo funziona per rinominare la prima chiave:

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

quindi, print_r ($ a) esegue il rendering di un array in ordine riparato:

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

funziona per rinominare una chiave arbitraria:

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

una funzione generalizzata:

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

    return array_flip($tmp_A);
}

1

Se si desidera sostituire più chiavi contemporaneamente (preservando l'ordine):

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

Uso:

$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

Esiste un modo alternativo per cambiare la chiave di un elemento dell'array quando si lavora con un array completo, senza cambiare l'ordine dell'array. È semplicemente copiare l'array in un nuovo array.

Ad esempio, stavo lavorando con un array misto e multidimensionale che conteneva chiavi indicizzate e associative - e volevo sostituire le chiavi intere con i loro valori, senza interrompere l'ordine.

L'ho fatto cambiando chiave / valore per tutte le voci di array numerici - qui: ['0' => 'pippo']. Si noti che l'ordine è intatto.

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

Produzione:

Array (
    [foo] => 
    [bar] => alfa
    [baz] => Array (
            [a] => hello
            [b] => world
        )
)

1

il modo migliore è usare il riferimento e non usare unset (che fa un altro passo per pulire la memoria)

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

soluzione:

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

hai un originale e un riferimento con un nuovo nome.

o se non si desidera avere due nomi in un valore è buono creare un'altra scheda e cercare su riferimento

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

Iterration è meglio sui tasti che clonare tutti gli array e pulire il vecchio array se si hanno dati lunghi come 100 righe +++ ecc.


0

Hmm, non ho provato prima, ma penso che questo codice funzioni

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 codifica e decodifica? Questa è una risposta davvero negativa.
kixorz,

0

Uno che preserva l'ordine è semplice da capire:

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

È possibile scrivere una funzione semplice che applica il callback ai tasti dell'array specificato. Simile a 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}}

Ecco una sintesi https://gist.github.com/vardius/650367e15abfb58bcd72ca47eff096ca#file-array_map_keys-php .


0

Questa funzione rinominerà una chiave dell'array, mantenendo la sua posizione, combinandola con la ricerca dell'indice.

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

Uso:

$arr = renameArrKey($arr, 'old_key', 'new_key');

-1

Questa funzione di base gestisce lo scambio dei tasti dell'array e mantiene l'array nell'ordine originale ...

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

È quindi possibile scorrere e scambiare tutti i tasti "a" con "z", ad esempio ...

$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);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.