Change key in associative array in PHP [duplicate]
Asked Answered
C

10

19

Say I have an array like this:

array(2) {
  [0]=> array(2) {
    ["n"]=> string(4) "john"
    ["l"]=> string(3) "red"
  }
  [1]=> array(2) {
    ["n"]=> string(5) "nicel"
    ["l"]=> string(4) "blue"
  }
}

How would I change the keys of the inside arrays? Say, I want to change "n" for "name" and "l" for "last_name". Taking into account that it can happen than an array doesn't have a particular key.

Crowboot answered 5/11, 2012 at 13:46 Comment(1)
Look at this: #241160Essam
C
24

Using array_walk

array_walk($array, function (& $item) {
   $item['new_key'] = $item['old_key'];
   unset($item['old_key']);
});
Correspondent answered 6/2, 2016 at 13:59 Comment(2)
where did that $item came from?Edo
@AlishaLamichhane $item will hold $array value.Conscription
P
19

Something like this maybe:

if (isset($array['n'])) {
    $array['name'] = $array['n'];
    unset($array['n']);
}

NOTE: this solution will change the order of the keys. To preserve the order, you'd have to recreate the array.

Protect answered 5/11, 2012 at 13:51 Comment(1)
I can see this working inside the foreach, but once outside it seems the values are still the old ones. I guess I needed to add "&".Crowboot
D
4

You could have:

  1. an array that maps the key exchange (to make the process parametrizable)
  2. a loop the processes the original array, accessing to every array item by reference

E.g.:

$array = array( array('n'=>'john','l'=>'red'), array('n'=>'nicel','l'=>'blue') );

$mapKeyArray = array('n'=>'name','l'=>'last_name');

foreach( $array as &$item )
{
    foreach( $mapKeyArray as $key => $replace )
    {
        if (key_exists($key,$item))
        {
            $item[$replace] = $item[$key];
            unset($item[$key]); 
        }
    }
}

In such a way, you can have other replacements simply adding a couple key/value to the $mapKeyArray variable.

This solution also works if some key is not available in the original array

Doggo answered 5/11, 2012 at 13:59 Comment(0)
B
1

Just make a note of the old value, use unset to remove it from the array then add it with the new key and the old value pair.

Barytes answered 5/11, 2012 at 13:50 Comment(0)
M
1

Renaming the key AND keeping the ordering consistent (the later was important for the use case that the following code was written).

<?php
/**
 * Rename a key and preserve the key ordering.
 *
 * An E_USER_WARNING is thrown if there is an problem.
 *
 * @param array &$data The data.
 * @param string $oldKey The old key.
 * @param string $newKey The new key.
 * @param bool $ignoreMissing Don't raise an error if the $oldKey does not exist.
 * @param bool $replaceExisting Don't raise an error if the $newKey already exists.
 *
 * @return bool True if the rename was successful or False if the old key cannot be found or the new key already exists.
 */
function renameKey(array &$data, $oldKey, $newKey, $ignoreMissing = false, $replaceExisting = false)
{
    if (!empty($data)) {
        if (!array_key_exists($oldKey, $data)) {
            if ($ignoreMissing) {
                return false;
            }

            return !trigger_error('Old key does not exist', E_USER_WARNING);
        } else {
            if (array_key_exists($newKey, $data)) {
                if ($replaceExisting) {
                    unset($data[$newKey]);
                } else {
                    return !trigger_error('New key already exists', E_USER_WARNING);
                }
            }

            $keys = array_keys($data);
            $keys[array_search($oldKey, array_map('strval', $keys))] = $newKey;
            $data = array_combine($keys, $data);

            return true;
        }
    }

    return false;
}

And some unit tests (PHPUnit being used, but hopefully understandable as the purpose of the tests).

public function testRenameKey()
{
    $newData = $this->data;
    $this->assertTrue(Arrays::renameKey($newData, 200, 'TwoHundred'));
    $this->assertEquals(
        [
            100 => $this->one,
            'TwoHundred' => $this->two,
            300 => $this->three,
        ],
        $newData
    );
}

public function testRenameKeyWithEmptyData()
{
    $newData = [];
    $this->assertFalse(Arrays::renameKey($newData, 'junk1', 'junk2'));
}

public function testRenameKeyWithExistingNewKey()
{
    Arrays::renameKey($this->data, 200, 200);
    $this->assertError('New key already exists', E_USER_WARNING);
}

public function testRenameKeyWithMissingOldKey()
{
    Arrays::renameKey($this->data, 'Unknown', 'Unknown');
    $this->assertError('Old key does not exist', E_USER_WARNING);
}

public function testRenameKeyWithMixedNumericAndStringIndicies()
{
    $data = [
        'nice', // Index 0
        'car' => 'fast',
        'none', // Index 1
    ];
    $this->assertTrue(Arrays::renameKey($data, 'car', 2));
    $this->assertEquals(
        [
            0 => 'nice',
            2 => 'fast',
            1 => 'none',
        ],
        $data
    );
}

The AssertError assertion is available for PHPUnit from https://github.com/digitickets/phpunit-errorhandler

Menides answered 10/11, 2017 at 11:44 Comment(2)
I would change: $keys[array_search($oldKey, $keys)] = $newKey; To: $keys[array_search($oldKey, array_map('strval', $keys))] = $newKey; Here's the issue I ran into: php.net/manual/en/function.array-search.php#122377 Also I was able to use your function w/ array_walk (recursively). Thanks!Riflery
Thank you @EllisGL. I've updated the answer with your comment, as well as a new unit test to cover this particular issue.Menides
N
0

You could use the array_flip function:

$original = array('n'=>'john','l'=>'red');
$flipped = array_flip($original);
foreach($flipped as $k => $v){
    $flipped[$k] = ($v === 'n' ? 'name' : ($v === 'l' ? 'last_name' : $v));
}
$correctedOriginal = array_flip($flipped);
Nagoya answered 28/5, 2015 at 10:17 Comment(1)
Only if you don't have duplicated values.Chanson
C
0
function arrayReplaceKey($array, $oldKey, $newKey) {
    $r = array();
    foreach ($array as $k => $v) {
        if ($k === $oldKey) $k = $newKey;
        $r[$k] = $v;
    }
    return $r;
}
Chanson answered 27/11, 2018 at 21:5 Comment(0)
I
0

Here is a solution to change the key of an array and also keep the original position within the array. It is intended for associative arrays. In my case the values were objects but I've simplified this example.

// Our array
$fields = array(
    'first_name' => 'Radley',
    'last_name' => 'Sustaire',
    'date' => '6/26/2019', // <== Want to rename the key from "date" to "date_db"
    'amazing' => 'yes',
);

// Get the field value
$date_field = $fields['date'];

// Get the key position in the array (numeric)
$key_position = array_search( 'date', array_keys($fields) );

// Remove the original value
unset($fields['date']);

// Add the new value back in, with the new key, at the old position
$fields = array_merge(
    array_slice( $fields, 0, $key_position, true ),
    array( 'date_db' => $date_field ), // Notice the new key ends with "_db"
    array_slice( $fields, $key_position, null, true )
);

/*
Input:
Array(
    [first_name] => Radley
    [last_name] => Sustaire
    [date] => 6/26/2019
    [amazing] => yes
)

Output:
Array(
    [first_name] => Radley
    [last_name] => Sustaire
    [date_db] => 6/26/2019
    [amazing] => yes
)
*/
Ionogen answered 28/6, 2019 at 6:16 Comment(0)
H
0

I had similar issue - to remove extra suffixes from the keys, and there it is:

$arr = [
    'first_name_blah' => 'John',
    'last_name_bloh' => 'Smith',
    'age_bloh' => 99,
    'sex_bloh' => 'm',
];

foreach ($arr as $k => $v) {
    $newKey = preg_replace('/(_blah|_bloh|_bleh)$/', '', $k);
    if ($newKey !== $k) {
        $arr[$newKey] = $v;
        unset($arr[$k]);
    }
}

/* Result:
Array
(
    [first_name] => John
    [last_name] => Smith
    [age] => 99
    [sex] => m
)
*/
    
Hilaria answered 20/4, 2023 at 10:22 Comment(0)
H
-1

Passed by reference

foreach($arr as &$m)
{
  $m['first_name'] = $m['n'];
  $m['last_name'] = $m['l'];
  unset($m['l'], m['n']);
}

print_r($arr);
Higher answered 6/1, 2021 at 10:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.