En PHP, comment changez-vous la clé d'un élément de tableau?

348

J'ai un tableau associatif sous la forme key => valueoù la clé est une valeur numérique, mais ce n'est pas une valeur numérique séquentielle. La clé est en fait un numéro d'identification et la valeur est un nombre. C'est très bien pour la plupart des instances, mais je veux une fonction qui obtient le nom lisible par l'homme du tableau et l'utilise pour la clé, sans changer la valeur.

Je n'ai pas vu une fonction qui fait cela, mais je suppose que je dois fournir l'ancienne clé et la nouvelle clé (que j'ai toutes les deux) et transformer le tableau. Existe-t-il un moyen efficace de procéder?

Thomas Owens
la source
Voir similaire stackoverflow.com/q/308703
Peter Krauss

Réponses:

576
$arr[$newkey] = $arr[$oldkey];
unset($arr[$oldkey]);
KernelM
la source
5
Faites juste attention à ce que 1) Il n'y ait pas deux clés ayant la même version lisible par l'homme 2) Aucune version lisible par l'homme ne se trouve être des nombres
Greg
81
Cela modifierait également probablement l'ordre du tableau, auquel vous devrez peut-être faire attention. Même les tableaux associatifs en PHP sont ordonnés, et parfois cet ordre est exploité.
Robin Winslow
7
Ouais, grand point Robin. Existe-t-il un moyen de conserver le même ordre? Ou avez-vous besoin de créer un nouveau tableau pour y parvenir?
Simon East
40
Question bonus: comment changer l'ID, mais conserver l'ordre des tableaux?
Petr Peller
17
si la valeur de la clé ne change pas, vous supprimerez un élément du tableau. Vous voudrez peut-être le vérifier.
Peeech
97

La façon de procéder et de conserver l'ordre du tableau consiste à placer les clés du tableau dans un tableau distinct, à rechercher et à remplacer la clé dans ce tableau, puis à la combiner à nouveau avec les valeurs.

Voici une fonction qui fait exactement cela:

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
la source
2
Merci, cela a été vraiment utile car j'avais besoin de préserver l'ordre du tableau. J'avais déjà essayé la réponse acceptée avant de trouver cette page.
gillytech
3
Oui, je préfère de beaucoup conserver l'ordre du tableau, semble plus soigné.
Phil Cook
2
J'ai dû conserver l'ordre des clés, bon, a fonctionné comme un charme!
Apprenant
Faites attention si vous voulez des performances ou la conservation des commandes: stackoverflow.com/a/58619985/1617857
Léo Benoist
54

si votre arrayest construit à partir d'une requête de base de données, vous pouvez modifier la clé directement à partir de l' mysqlinstruction:

au lieu de

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

utilisez quelque chose comme:

"select ´id´ **as NEWNAME** from ´tablename´..."
Simon Franco
la source
grande réponse, très précieuse!
DevMoutarde
20

La réponse de KernelM est agréable, mais afin d'éviter le problème soulevé par Greg dans le commentaire (clés en conflit), l'utilisation d'un nouveau tableau serait plus sûre

$newarr[$newkey] = $oldarr[$oldkey];
$oldarr=$newarr;
unset($newarr);
kjg
la source
C'est une bonne solution, tant que votre baie est de taille raisonnable. Si votre tableau consomme plus de la moitié de la mémoire PHP disponible, cela ne fonctionnera pas.
kingjeffrey
12
@kingjeffrey, pas vraiment. Les valeurs de tableau ne seront pas dupliquées tant qu'elles sont "juste copiées" sans être modifiées. Par exemple, s'il y a un tableau qui contient 10 000 éléments et consomme 40 Mo de mémoire, sa copie consommera la mémoire nécessaire pour stocker 10 000 uniquement des références à des valeurs déjà existantes plutôt que des copies de valeurs , donc si 1 tableau consomme 40 Mo, sa copie pourrait consommer peut-être 0,5 Mo (testé).
binaryLV
17

Vous pouvez utiliser un deuxième tableau associatif qui mappe les noms lisibles par l'homme aux identifiants. Cela fournirait également une relation plusieurs à un. Ensuite, faites quelque chose comme ceci:

echo 'Widgets: ' . $data[$humanreadbleMapping['Widgets']];
Tom Ritter
la source
11

Si vous souhaitez également que la position de la nouvelle clé de tableau soit la même que l'ancienne, vous pouvez le faire:

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
la source
7

Si votre tableau est récursif, vous pouvez utiliser cette fonction: testez ces données:

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

voici la fonction:

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
la source
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
];
*/
temuri
la source
3
Je m'aime mes fonctions de tableau. J'étais sur le point de suggérer cela comme une belle ligne pour renommer toutes les clés et maintenir l'ordre des tableaux, mais je recommanderai la vôtre à la place.
Automne Leonard
6

J'aime la solution de KernelM, mais j'avais besoin de quelque chose qui puisse gérer les conflits de clés potentiels (où une nouvelle clé peut correspondre à une clé existante). Voici ce que j'ai trouvé:

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

Vous pouvez ensuite parcourir un tableau comme celui-ci:

$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
la source
6

Voici une fonction d'aide pour y parvenir:

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

assez basé sur la réponse @KernelM .

Usage:

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

Il renverra true en cas de renommage réussi, sinon false .

kenorb
la source
Sachez que cela modifie l'ordre du tableau (l'élément de la clé renommée sera à la fin du tableau, pas dans la même position dans le tableau qu'elle l'était à l'origine). De plus, je ne démarre généralement pas un nom de fonction avec un trait de soulignement (qui est traditionnellement utilisé pour désigner des fonctions spéciales à usage interne).
2016
4

Trucs faciles:

cette fonction acceptera le hash $ cible et $ les remplacements est aussi un hash contenant des associations newkey => oldkey .

Cette fonction conservera l'ordre d'origine , mais pourrait être problématique pour les très grands tableaux (comme les enregistrements supérieurs à 10k) concernant les performances et la mémoire .

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

cette fonction alternative ferait de même, avec des performances et une utilisation de la mémoire bien meilleures , au prix de la perte de la commande d'origine (ce qui ne devrait pas être un problème car elle est 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;       
}
Nadir
la source
4

ce code aidera à changer l'ancienne clé en une nouvelle

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

afficher comme

$keys_array=array("one"=>"one","two"=>"two");
karthikeyan ganesan
la source
3

Comparaison de référence simple des deux solutions.

Solution 1 Copiez et supprimez (commande perdue) https://stackoverflow.com/a/240676/1617857

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

Solution 2 Renommez la clé 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 );
}

Résultats:

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
Léo Benoist
la source
2

Vous pouvez utiliser cette fonction basée sur 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));

Il donne:

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
la source
1

cela fonctionne pour renommer la première clé:

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

ensuite, print_r ($ a) rend un tableau dans l'ordre réparé:

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

cela fonctionne pour renommer une clé arbitraire:

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

une fonction généralisée:

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

    return array_flip($tmp_A);
}
wmmso
la source
1

Si vous souhaitez remplacer plusieurs clés à la fois (en préservant l'ordre):

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

Usage:

$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);
lepe
la source
1

Il existe une autre façon de modifier la clé d'un élément de tableau lorsque vous travaillez avec un tableau complet - sans changer l'ordre du tableau. Il s'agit simplement de copier le tableau dans un nouveau tableau.

Par exemple, je travaillais avec un tableau mixte multidimensionnel qui contenait des clés indexées et associatives - et je voulais remplacer les clés entières par leurs valeurs, sans casser l'ordre.

Je l'ai fait en changeant la clé / valeur pour toutes les entrées du tableau numérique - ici: ['0' => 'foo']. Notez que la commande est intacte.

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

Production:

Array (
    [foo] => 
    [bar] => alfa
    [baz] => Array (
            [a] => hello
            [b] => world
        )
)
Kristoffer Bohmann
la source
1

la meilleure façon est d'utiliser la référence, et non d'utiliser unset (ce qui fait une autre étape pour nettoyer la mémoire)

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

Solution:

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

vous avez un original et une référence avec un nouveau nom.

ou si vous ne voulez pas avoir deux noms dans une valeur c'est bien faire un autre onglet et foreach sur référence

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

L'itération est meilleure sur les clés que le clonage de tous les tableaux, et le nettoyage de l'ancien tableau si vous avez des données longues comme 100 lignes +++ etc.

Kamil Dąbrowski
la source
0

Hmm, je ne fais pas de test avant, mais je pense que ce code fonctionne

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);
}
Frank Vu
la source
Json encode et décode? C'est une très mauvaise réponse.
kixorz
0

Celui qui préserve l'ordre qui est simple à comprendre:

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;
}
Andrew
la source
0

Vous pouvez écrire une fonction simple qui applique le rappel aux clés du tableau donné. Similaire à 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}}

Voici un résumé https://gist.github.com/vardius/650367e15abfb58bcd72ca47eff096ca#file-array_map_keys-php .

vardius
la source
0

Cette fonction renommera une clé de tableau, en conservant sa position, en combinant avec la recherche d'index.

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

Usage:

$arr = renameArrKey($arr, 'old_key', 'new_key');
Subvention
la source
-1

Cette fonction de base gère l'échange de clés de tableau et le maintien du tableau dans l'ordre d'origine ...

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

Vous pouvez ensuite parcourir et échanger toutes les clés 'a' avec 'z' par exemple ...

$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
la source