No PHP, como você altera a chave de um elemento da matriz?

348

Eu tenho uma matriz associativa no formulário em key => valueque chave é um valor numérico, no entanto, não é um valor numérico seqüencial. A chave é realmente um número de identificação e o valor é uma contagem. Isso é bom para a maioria dos casos, no entanto, quero uma função que obtenha o nome legível por humanos da matriz e use-o para a chave, sem alterar o valor.

Eu não vi uma função que faz isso, mas estou assumindo que preciso fornecer a chave antiga e a nova chave (ambas as quais tenho) e transformar a matriz. Existe uma maneira eficiente de fazer isso?

Thomas Owens
fonte
Veja similar stackoverflow.com/q/308703
Peter Krauss

Respostas:

576
$arr[$newkey] = $arr[$oldkey];
unset($arr[$oldkey]);
KernelM
fonte
5
Basta ter cuidado que: 1) Não há duas teclas têm a mesma versão legível 2) Não há versões legíveis acontecer de ser números
Greg
81
Presumivelmente, isso provavelmente mudaria a ordem da matriz, da qual você pode precisar ter cuidado. Até matrizes associativas em PHP são ordenadas e, às vezes, essa ordem é alavancada.
Robin Winslow
7
Sim, ótimo ponto Robin. Existe uma maneira de manter a mesma ordem? Ou você precisa criar uma nova matriz para conseguir isso?
Simon Médio
40
Pergunta de bônus: Como alterar o ID, mas preservar a ordem do array?
precisa
17
se o valor da chave não estiver sendo alterado, você excluirá um elemento da matriz. Você pode querer verificar isso.
Peeech
97

A maneira como você faria isso e preservaria a ordem da matriz é colocando as chaves da matriz em uma matriz separada, localize e substitua a chave nessa matriz e combine-a novamente com os valores.

Aqui está uma função que faz exatamente isso:

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
fonte
2
Graças isso foi realmente útil, pois eu precisava preservar a ordem da matriz. Eu já havia tentado a resposta aceita antes de encontrar esta página.
Gillytech #
3
Sim, prefiro preservar a ordem da matriz, parece mais limpo.
Phil Cook
2
Tinha que preservar a ordem das chaves, boa, funcionou como um encanto!
Learner
Importe-se se você quer performances ou preservação de pedidos: stackoverflow.com/a/58619985/1617857
Léo Benoist
54

se o seu arrayfor construído a partir de uma consulta ao banco de dados, você poderá alterar a chave diretamente da mysqlinstrução:

ao invés de

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

use algo como:

"select ´id´ **as NEWNAME** from ´tablename´..."
Simon Franco
fonte
ótima resposta, muito valiosa!
DevMoutarde
20

A resposta do KernelM é boa, mas para evitar o problema levantado por Greg no comentário (chaves conflitantes), o uso de uma nova matriz seria mais seguro

$newarr[$newkey] = $oldarr[$oldkey];
$oldarr=$newarr;
unset($newarr);
kjg
fonte
Essa é uma boa solução, desde que sua matriz tenha um tamanho razoável. Se sua matriz consumir mais da metade da memória PHP disponível, isso não funcionará.
kingjeffrey
12
@kingjeffrey, na verdade não. Os valores da matriz não serão duplicados desde que sejam "apenas copiados" sem serem modificados. Por exemplo, se houver uma matriz que contém 10.000 elementos e consome 40 MB de memória, a cópia consumirá a memória necessária para armazenar 10.000 referências apenas a valores já existentes, em vez de cópias de valores ; portanto, se 1 matriz consumir 40 MB, sua cópia pode consumir talvez 0,5 MB (testado).
precisa
17

Você pode usar uma segunda matriz associativa que mapeia nomes legíveis por humanos para os IDs. Isso também forneceria um relacionamento Muitos para 1. Então faça algo parecido com isto:

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

Se você também deseja que a posição da nova chave de matriz seja a mesma que a antiga, você pode fazer isso:

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

Se sua matriz é recursiva, você pode usar esta função: teste estes dados:

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

aqui está a função:

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
fonte
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
fonte
3
Eu me amo minhas funções de matriz. Eu estava prestes a sugerir isso como uma única linha agradável para renomear todas as chaves e manter a ordem da matriz, mas eu recomendo a sua.
Autumn Leonard
6

Eu gosto da solução do KernelM, mas precisava de algo que lidasse com possíveis conflitos de chave (onde uma nova chave pode corresponder a uma chave existente). Aqui está o que eu vim com:

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

Você pode então percorrer uma 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
fonte
6

Aqui está uma função auxiliar para conseguir isso:

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

bastante baseado na resposta do @KernelM .

Uso:

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

Retornará true ao renomear com êxito, caso contrário, false .

kenorb
fonte
Esteja ciente de que isso altera a ordem da matriz (o elemento da chave renomeada estará no final da matriz, não na mesma posição na matriz como era originalmente). Além disso, eu normalmente não iniciava o nome de uma função com um sublinhado (tradicionalmente usado para designar funções especiais de uso interno).
orrd 18/06/16
4

Coisas fáceis:

esta função aceitará o destino $ hash e $ substitutions também é um hash que contém associações newkey => oldkey .

Essa função preserva a ordem original , mas pode ser problemática para matrizes muito grandes (como acima de 10k) em relação ao desempenho e à memória .

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

essa função alternativa faria o mesmo, com desempenho e uso de memória muito melhores , com o custo de perder a ordem original (o que não deve ser um problema, pois é 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
fonte
4

esse código ajudará a mudar a chave antiga para a nova

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

exibir como

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

Comparação simples de benchmark de ambas as soluções.

Solução 1 Copie e remova (pedido perdido) https://stackoverflow.com/a/240676/1617857

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

Solução 2 Renomeie a chave 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
fonte
2

Você pode usar esta função com base em 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
    )
)
Alekzander
fonte
1

isso funciona para renomear a primeira chave:

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

Em seguida, print_r ($ a) renderiza uma matriz em ordem reparada:

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

isso funciona para renomear uma chave arbitrária:

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

uma função generalizada:

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

    return array_flip($tmp_A);
}
wmmso
fonte
1

Se você deseja substituir várias chaves ao mesmo tempo (preservando a ordem):

/**
 * 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
fonte
1

Existe uma maneira alternativa de alterar a chave de um elemento da matriz ao trabalhar com uma matriz completa - sem alterar a ordem da matriz. É simplesmente copiar a matriz para uma nova matriz.

Por exemplo, eu estava trabalhando com uma matriz multidimensional e multidimensional que continha chaves associativas e indexadas - e queria substituir as chaves inteiras por seus valores, sem quebrar a ordem.

Eu fiz isso alternando chave / valor para todas as entradas numéricas da matriz - aqui: ['0' => 'foo']. Observe que o 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);

Resultado:

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

A melhor maneira é usar a referência e não usar a configuração (o que faz outra etapa para limpar a memória)

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

solução:

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

você tem um original e uma referência com novo nome.

ou se você não quiser ter dois nomes em um valor é bom, crie outra guia e foreach na referência

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

A Iterration é melhor nas chaves do que clonar toda a matriz e limpar a matriz antiga se você tiver dados longos, como 100 linhas +++ etc.

Kamil Dąbrowski
fonte
0

Hmm, não testei antes, mas acho que esse código está funcionando

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
fonte
Json codifica e decodifica? Esta é uma resposta muito ruim.
Kixorz
0

Um que preserva a ordenação simples 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;
}
Andrew
fonte
0

Você pode escrever uma função simples que aplica o retorno de chamada às chaves da matriz especificada. Semelhante ao 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}}

Aqui está uma lista https://gist.github.com/vardius/650367e15abfb58bcd72ca47eff096ca#file-array_map_keys-php .

vardius
fonte
0

Essa função renomeará uma chave de matriz, mantendo sua posição, combinando com a pesquisa 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
fonte
-1

Essa função básica lida com a troca de chaves da matriz e a manutenção da ordem na ordem 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;
}

Você poderia fazer um loop e trocar todas as chaves 'a' por 'z', por exemplo ...

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