Fastest way to add prefix to array keys?

What is the fastest way to add string prefixes to array keys?

Input

$array = array(
 '1' => 'val1',
 '2' => 'val2',
);

Needed output:

$array = array(
  'prefix1' => 'val1',
  'prefix2' => 'val2',
);

Solution 1:

Could do this in one long line I presume:

$array = array_combine(
    array_map(function($k){ return 'prefix'.$k; }, array_keys($array)),
    $array
);

Or for versions of PHP prior to 5.3:

$array = array_combine(
    array_map(create_function('$k', 'return "prefix".$k;'), array_keys($array)),
    $array
);

There's probably dozens of ways to do this though:

foreach ($array as $k => $v)
{
    $array['prefix_'.$k] = $v;
    unset($array[$k]);
}

Solution 2:

I've found that PHPBench is not a very good source for non-trivial benchmarks. So unless your actually interested in running for(....); it's not going to correctly show which syntax will be faster. I've put together a simple benchmark to show that foreach is actually the fastest when your use both the key and value during the iteration.

It's very important to actually force PHP to read the values from a loop iteration, or else it'll do its best to optimize them out. In the example below I use the doNothing function to force PHP to calculate the key and value each time. Using doNothing will cause an overhead to be applied to each loop, but it will be the same for each loop since the number of calls will be the same.

I wasn't really that surprised that foreach came out on top since it's the language construct for iterating a dictionary.

$array = range( 0, 1000000 );

function doNothing( $value, $key ) {;}

$t1_start = microtime(true);
foreach( $array as $key => $value ) {
    doNothing( $value, $key );
}
$t1_end = microtime(true);

$t2_start = microtime(true);
$array_size = count( $array );
for( $key = 0; $key < $array_size; $key++ ) {
    doNothing( $array[$key], $key );
}
$t2_end = microtime(true);

    //suggestion from PHPBench as the "fastest" way to iterate an array
$t3_start = microtime(true);
$key = array_keys($array);
$size = sizeOf($key);
for( $i=0; $i < $size; $i++ ) {
    doNothing( $key[$i], $array[$key[$i]] );
}
$t3_end = microtime(true);

$t4_start = microtime(true);
array_walk( $array, "doNothing" );
$t4_end = microtime(true);

print
    "Test 1 ".($t1_end - $t1_start)."\n". //Test 1 0.342370986938
    "Test 2 ".($t2_end - $t2_start)."\n". //Test 2 0.369848966599
    "Test 3 ".($t3_end - $t3_start)."\n". //Test 3 0.78616809845
    "Test 4 ".($t4_end - $t4_start)."\n"; //Test 4 0.542922019958

Edit: I'm using PHP 5.3 on 64-bit Mac OSX 10.6

Solution 3:

function keyprefix($keyprefix, Array $array) {

    foreach($array as $k=>$v){
        $array[$keyprefix.$k] = $v;
        unset($array[$k]);
    }

    return $array; 
}

Using array_flip will not preserve empty or null values. Additional code could be added in the unlikely event that the prefixed key already exists.

Solution 4:

If you don't want to use for loop you can do:

// function called by array_walk to change the $value  in $key=>$value.
function myfunction(&$value,$key) {
    $value="prefix$value";
}

$keys = array_keys($array);  // extract just the keys.
array_walk($keys,"myfunction"); // modify each key by adding a prefix.
$a = array_combine($keys,array_values($array)); // combine new keys with old values.

I don't think this will be more efficient than the for loop. I guess array_walk will internally use a loop and there is also the function call overhead here.