En PHP, ¿cómo se cambia la clave de un elemento de matriz?

348

Tengo una matriz asociativa en la forma key => valueen que la clave es un valor numérico, sin embargo, no es un valor numérico secuencial. La clave es en realidad un número de identificación y el valor es un recuento. Esto está bien para la mayoría de los casos, sin embargo, quiero una función que obtenga el nombre legible por humanos de la matriz y lo use para la clave, sin cambiar el valor.

No vi una función que haga esto, pero supongo que necesito proporcionar la clave antigua y la clave nueva (las cuales tengo) y transformar la matriz. ¿Hay una manera eficiente de hacer esto?

Thomas Owens
fuente
Ver similar stackoverflow.com/q/308703
Peter Krauss

Respuestas:

576
$arr[$newkey] = $arr[$oldkey];
unset($arr[$oldkey]);
KernelM
fuente
55
Solo tenga cuidado de que 1) No hay dos claves que tengan la misma versión legible por humanos 2) No hay versiones legibles por humanos que sean números
Greg
81
Además, esto presumiblemente cambiaría el orden de la matriz, de lo que es posible que tenga que tener cuidado. Incluso las matrices asociativas en PHP están ordenadas y, a veces, ese orden se aprovecha.
Robin Winslow
77
Sí, gran punto Robin. ¿Hay alguna manera de mantener el mismo orden? ¿O necesita crear una nueva matriz para lograr eso?
Simon East
40
Pregunta adicional: ¿Cómo cambiar la ID, pero preservar el orden de la matriz?
Petr Peller
17
Si el valor clave no cambia, eliminará un elemento de matriz. Es posible que desee verificarlo.
Peeech
97

La forma en que haría esto y preservaría el orden de la matriz es colocando las claves de la matriz en una matriz separada, encuentre y reemplace la clave en esa matriz y luego vuelva a combinarla con los valores.

Aquí hay una función que hace exactamente eso:

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
fuente
2
Gracias, esto fue realmente útil, ya que necesitaba preservar el orden de la matriz. Ya había probado la respuesta aceptada antes de encontrar esta página.
gillytech
3
Sí, prefiero preservar el orden de la matriz, se ve más ordenado.
Phil Cook
2
Tuve que preservar el orden de las claves, bueno, funcionó a las mil maravillas!
Estudiante
Tenga en cuenta si desea actuaciones o preservación de pedidos: stackoverflow.com/a/58619985/1617857
Léo Benoist
54

si su arrayse construye a partir de una consulta de base de datos, puede cambiar la clave directamente desde la mysqldeclaración:

en vez de

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

usa algo como:

"select ´id´ **as NEWNAME** from ´tablename´..."
Simon Franco
fuente
gran respuesta, muy valiosa!
DevMoutarde
20

La respuesta de KernelM es buena, pero para evitar el problema planteado por Greg en el comentario (claves en conflicto), usar una nueva matriz sería más seguro

$newarr[$newkey] = $oldarr[$oldkey];
$oldarr=$newarr;
unset($newarr);
kjg
fuente
Esta es una buena solución, siempre que su matriz tenga un tamaño razonable. Si su matriz consume más de la mitad de la memoria PHP disponible, esto no funcionará.
kingjeffrey
12
@kingjeffrey, en realidad no. Los valores de la matriz no se duplicarán mientras se "copien" sin modificarse. Por ejemplo, si hay una matriz que contiene 10'000 elementos y consume 40MB de memoria, copiarla consumirá la memoria necesaria para almacenar 10'000 solo referencias a valores ya existentes en lugar de copias de valores , por lo que si 1 matriz consume 40MB, su copia podría consumir quizás 0.5 MB (probado).
binaryLV
17

Podría usar una segunda matriz asociativa que asigne nombres legibles por humanos a los id. Eso también proporcionaría una relación de Muchos a 1. Entonces haz algo como esto:

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

Si desea que la posición de la nueva clave de matriz sea la misma que la anterior, puede hacer esto:

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;
}
propagación
fuente
7

Si su matriz es recursiva, puede usar esta función: pruebe estos datos:

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

Aquí está la función:

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;   
}
pijafumo
fuente
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
fuente
3
Me encantan mis funciones de matriz. Estaba a punto de sugerir esto como una buena frase para cambiar el nombre de todas las claves y mantener el orden de la matriz, pero recomendaré la suya en su lugar.
Otoño Leonard
6

Me gusta la solución de KernelM, pero necesitaba algo que pudiera manejar posibles conflictos de clave (donde una nueva clave puede coincidir con una clave existente). Esto es lo que se me ocurrió:

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

Luego puede recorrer una matriz como esta:

$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
fuente
6

Aquí hay una función auxiliar para lograr eso:

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

Basada en la respuesta de @KernelM .

Uso:

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

Volverá verdadero en cambio de nombre exitoso, de lo contrario falso .

kenorb
fuente
Tenga en cuenta que esto altera el orden de la matriz (el elemento de la clave renombrada estará al final de la matriz, no en la misma posición en la matriz como estaba originalmente). Además, normalmente no comenzaría un nombre de función con un guión bajo (que se usa tradicionalmente para designar funciones especiales de uso interno).
orden
4

Cosas fáciles:

esta función aceptará el objetivo $ hash y $ reemplazos también es un hash que contiene asociaciones newkey => oldkey .

Esta función preservará el orden original , pero podría ser problemático para matrices muy grandes (como los registros de más de 10k) con respecto al rendimiento y la 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;    
}

esta función alternativa haría lo mismo, con un rendimiento y uso de memoria mucho mejores , a costa de perder el pedido original (¡lo cual no debería ser un problema ya que es 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
fuente
4

este código ayudará a cambiar la clave antigua a una nueva

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

mostrar como

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

Comparación simple de referencia de ambas soluciones.

Solución 1 Copiar y eliminar (pedido perdido) https://stackoverflow.com/a/240676/1617857

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

Solución 2 Cambie el nombre de la clave 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 );
}

Resultados:

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
fuente
2

Puede usar esta función basada en 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));

Da:

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
fuente
1

esto funciona para renombrar la primera clave:

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

luego, print_r ($ a) renderiza una matriz en orden reparada:

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

esto funciona para renombrar una clave 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 función generalizada:

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

    return array_flip($tmp_A);
}
wmmso
fuente
1

Si desea reemplazar varias teclas a la vez (preservar el orden):

/**
 * 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);
lepe
fuente
1

Hay una forma alternativa de cambiar la clave de un elemento de matriz cuando se trabaja con una matriz completa, sin cambiar el orden de la matriz. Es simplemente copiar la matriz en una nueva matriz.

Por ejemplo, estaba trabajando con una matriz mixta y multidimensional que contenía claves indexadas y asociativas, y quería reemplazar las claves enteras con sus valores, sin romper el orden.

Lo hice cambiando la clave / valor para todas las entradas de matriz numérica, aquí: ['0' => 'foo']. Tenga en cuenta que el pedido está intacto.

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

Salida:

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

La mejor manera es usar referencia y no usar unset (lo que hace otro paso para limpiar la memoria)

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

solución:

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

Tiene una referencia original y otra con un nombre nuevo.

o si no quiere tener dos nombres en un valor es bueno, haga otra pestaña y consulte la referencia

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

La iteración es mejor en las claves que clonar toda la matriz y limpiar la matriz anterior si tiene datos largos como 100 filas +++, etc.

Kamil Dąbrowski
fuente
0

Hmm, no estoy probado antes, pero creo que este código funciona

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
fuente
¿Json codifica y decodifica? Esta es una muy mala respuesta.
kixorz
0

Uno que ordena los conservantes que es fácil de entender:

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;
}
Andrés
fuente
0

Puede escribir una función simple que aplique la devolución de llamada a las teclas de la matriz dada. Similar 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}}

Aquí hay un resumen https://gist.github.com/vardius/650367e15abfb58bcd72ca47eff096ca#file-array_map_keys-php .

vardius
fuente
0

Esta función cambiará el nombre de una clave de matriz, manteniendo su posición, combinándola con la búsqueda de índice.

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');
Conceder
fuente
-1

Esta función básica maneja el intercambio de claves de matriz y mantiene la matriz en el orden original ...

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

Luego, puede recorrer e intercambiar todas las teclas 'a' con 'z', por ejemplo ...

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