PHP'de, bir dizi öğesinin anahtarını nasıl değiştirirsiniz?


348

key => valueAnahtar sayısal bir değer olduğu halde ilişkili bir dizi var , ancak sıralı sayısal bir değer değil. Anahtar aslında bir kimlik numarasıdır ve değer bir sayıdır. Bu çoğu örnek için iyi, ancak ben dizinin insan tarafından okunabilir adını alır ve değeri değiştirmeden anahtar için kullanır bir işlev istiyorum.

Bunu yapan bir işlev görmedim, ama eski anahtar ve yeni anahtar (her ikisi de ben var) sağlamak ve dizi dönüştürmek gerekiyor varsayalım. Bunu yapmanın etkili bir yolu var mı?


Yanıtlar:


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

5
Sadece 1) Hayır iki anahtar aynı insan tarafından okunabilir sürüm 2) Hayır insan tarafından okunabilir versiyonları sayılar olmak olur olduğunu dikkatli olun
Greg

81
Ayrıca bu muhtemelen dikkat etmeniz gereken dizinin sırasını değiştirir. PHP'deki ilişkisel diziler bile sıralanır ve bazen bu düzen kullanılır.
Robin Winslow

7
Evet, harika bir nokta Robin. Aynı siparişi korumanın bir yolu var mı? Yoksa bunu başarmak için yeni bir dizi mi oluşturmanız gerekiyor?
Simon East

40
Bonus soru: Kimliği nasıl değiştirebilirim, ancak dizi sırasını nasıl koruyabilirim?
Petr Peller

17
eğer anahtar değeri değişmezse, bir dizi öğesini sileceksiniz. Bunu kontrol etmek isteyebilirsiniz.
Peeech

97

Bunu yapmanın ve dizinin sırasını korumanın yolu, dizi anahtarlarını ayrı bir diziye koyarak, o dizideki anahtarı bulup değiştirip değerleri ile birleştirmektir.

İşte bunu yapan bir işlev:

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
Dizinin sırasını korumak gerek yoktu teşekkürler bu gerçekten yararlı oldu. Bu sayfayı bulmadan önce kabul edilen yanıtı denemiştim.
gillytech

3
Evet çok dizinin sırasını korumak tercih, daha temiz görünüyor.
Phil Cook

2
Anahtar sipariş, iyi bir korumak zorunda kaldı, bir cazibe gibi çalıştı!
Öğrenci

Performans veya sipariş koruması istiyorsanız sorun: stackoverflow.com/a/58619985/1617857
Léo Benoist

54

eğer senin arraybir veritabanı sorgusu oluşmuşken, doğrudan 'dan anahtarını değiştirebilirsiniz mysqlaçıklamada:

onun yerine

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

gibi bir şey kullanın:

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

harika cevap, çok değerli!
DevMoutarde

20

KernelM'in cevabı güzel, ancak Greg'in yorumda (çakışan anahtarlar) ortaya çıkardığı sorunu önlemek için yeni bir dizi kullanmak daha güvenli olurdu

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

Diziniz makul bir boyutta olduğu sürece bu iyi bir çözümdür. Diziniz kullanılabilir PHP belleğinin yarısından fazlasını kullanıyorsa, bu çalışmaz.
kingjeffrey

12
@kingjeffrey, pek değil. Dizi değerleri, değiştirilmeden "yalnızca kopyalandığı" sürece çoğaltılmaz. Örneğin, 10.000 öğe içeren ve 40 MB bellek tüketen bir dizi varsa, kopyalamak , değerlerin kopyaları yerine yalnızca 10.000 değerindeki mevcut referanslara başvurmak için gereken belleği tüketir; bu nedenle 1 dizi 40 MB tüketirse, kopyası 0,5 MB (test edilmiş) tüketebilir.
binaryLV

17

İnsan tarafından okunabilir adları kimliklerle eşleyen ikinci bir ilişkilendirilebilir dizi kullanabilirsiniz. Bu aynı zamanda Çoktan Bire ilişki de sağlayacaktır. Sonra böyle bir şey yapın:

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

11

Yeni dizi anahtarının konumunun eskisiyle aynı olmasını istiyorsanız, bunu yapabilirsiniz:

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

Diziniz özyinelemeli ise şu işlevi kullanabilirsiniz: bu verileri test edin:

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

İşte işlevi:

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
Dizi işlevlerimi seviyorum. Bunu tüm anahtarları yeniden adlandırmak ve dizi sırasını korumak için güzel bir tek astar olarak önermek üzereydim, ancak bunun yerine sizinkini tavsiye edeceğim.
Sonbahar Leonard

6

KernelM'in çözümünü seviyorum, ancak potansiyel anahtar çakışmalarını (yeni bir anahtarın mevcut bir anahtarla eşleşebileceği) ele alacak bir şeye ihtiyacım vardı. İşte ben geldim:

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

Daha sonra şöyle bir dizi arasında geçiş yapabilirsiniz:

$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

İşte bunu başarmak için yardımcı bir fonksiyon:

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

Oldukça dayalı @KernelM cevap .

Kullanımı:

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

Başarılı yeniden adlandırmada true döndürür , aksi takdirde false olur .


Bunun, dizinin sırasını değiştirdiğini unutmayın (yeniden adlandırılan anahtarın öğesi, dizideki başlangıçtaki ile aynı konumda değil, dizinin sonunda olur). Ayrıca genellikle alt çizgiyle bir işlev adı başlatmazdım (geleneksel olarak özel iç kullanım işlevlerini belirtmek için kullanılır).
orrd

4

Kolay şeyler:

bu fonksiyon $ hash hedefini kabul eder ve $ replacements da newkey => oldkey ilişkilendirmelerini içeren bir hashtır .

Bu işlev orijinal sırayı koruyacaktır , ancak performans ve bellekle ilgili çok büyük (10k kayıtların üstünde) diziler için sorunlu olabilir .

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

Bu alternatif işlev, orijinal siparişi kaybetme pahasına çok daha iyi performans ve bellek kullanımı ile aynı şeyi yapacaktır (hashtable olduğundan bir sorun olmamalıdır!)

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

bu kod oldkey'i yenisiyle değiştirmeye yardımcı olacaktır

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

gibi göster

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

3

Her iki çözümün basit kıyaslama karşılaştırması.

Çözüm 1 Kopyalama ve kaldırma (sipariş kaybı) https://stackoverflow.com/a/240676/1617857

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

Çözüm 2 Anahtarı yeniden adlandırın 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 );
}

Sonuçlar:

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

Bu işlevi array_walk'a dayalı olarak kullanabilirsiniz:

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

O verir:

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

ilk anahtarı yeniden adlandırmak için çalışır:

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

ardından print_r ($ a), onarılan bir sipariş dizisi oluşturur:

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

bu, keyfi bir anahtarı yeniden adlandırmak için çalışır:

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

genelleştirilmiş bir işlev:

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

    return array_flip($tmp_A);
}

1

Birden fazla anahtarı aynı anda değiştirmek istiyorsanız (siparişi koruyarak):

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

Kullanımı:

$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

Tam bir diziyle çalışırken, dizinin sırasını değiştirmeden dizi öğesinin anahtarını değiştirmenin alternatif bir yolu vardır. Diziyi yeni bir diziye kopyalamak yeterlidir.

Örneğin, dizinli ve ilişkilendirilebilir anahtarlar içeren karışık, çok boyutlu bir dizi ile çalışıyordum ve sırayı bozmadan tamsayı anahtarlarını değerleriyle değiştirmek istedim.

Bunu tüm sayısal dizi girişleri için anahtar / değer değiştirerek yaptım - burada: ['0' => 'foo']. Siparişin eksiksiz olduğunu unutmayın.

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

Çıktı:

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

1

En iyi yol referans kullanmak ve unset kullanmamak (hafızayı temizlemek için başka bir adım atıyor)

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

çözüm:

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

bir orijinal ve bir yeni isimle referansınız var.

ya da bir değerde iki ismin olmasını istemiyorsanız başka bir sekme yapın ve referans için öngörü

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

Iterration tuşlarda tüm dizileri klonlamaktan daha iyidir ve 100 sıra +++ vb.Gibi uzun verileriniz varsa eski diziyi temizlemek.


0

Hmm, daha önce test etmiyorum, ama bence bu kod çalışıyor

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 kodlamak ve kodunu çözmek? Bu gerçekten kötü bir cevap.
kixorz

0

Koruyucular siparişi olanı anlamak kolaydır:

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

Belirli bir dizinin tuşlarına geri arama uygulayan basit bir işlev yazabilirsiniz. Array_map benzer

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

İşte bir özgeçmiş https://gist.github.com/vardius/650367e15abfb58bcd72ca47eff096ca#file-array_map_keys-php .


0

Bu işlev, dizin arama ile birleştirerek konumunu koruyarak bir dizi anahtarını yeniden adlandırır.

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

Kullanımı:

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

-1

Bu temel işlev, dizi anahtarlarını değiştirmeyi ve diziyi orijinal sırada tutmayı yönetir ...

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

Daha sonra tüm 'a' tuşlarını 'z' ile değiştirebilir ve değiştirebilirsiniz ...

$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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.