7

Is there a "better" way (built-in function, better algorithm) to normalize the case of all the keys in a PHP array? Looping though and creating a new array works

$new = array();
foreach( $old as $key=>$value) {
    $key = strToLower($key);
    if(!array_key_exists($key,$new) {
        $new[$key] = $value;
    } 
    else {
        throw new Exception('Duplicate Key Encountered');
    }

}

but it seems like these should be a way to do this "in place".

Update: It looks like there is a built in, the not deceptively named yet somehow missed by me array_change_key_case. I'd still be interesting in seeing algorithmic approaches that would let you better handle what happens when you hit "duplicate" keys.

Alana Storm
  • 164,128
  • 91
  • 395
  • 599
  • For the algorithmic approach I'd go with with soulmerge's "pragmatic" version below. – acrosman Jul 23 '09 at 14:10
  • [This post](http://blog.jterminal.com/2014/07/change-the-case-of-all-keys-in-an-array-with-array_change_key_case-function-in-php.html) explains what you need – Jasir Jul 10 '14 at 21:06

5 Answers5

13

I believe array_change_key_case does what you're looking for.

http://us3.php.net/manual/en/function.array-change-key-case.php

acrosman
  • 12,814
  • 10
  • 39
  • 55
4

I found that builtin functions are much faster than loops when processing large arrays. This might do what you want (untested code):

$lowerCaseKeys = array_map('strtolower', array_keys($array));
$duplicates = array_filter(array_count_values($lowerCaseKeys), create_function('$count', 'return $count > 1;'));
if (!empty($duplicates)) {
    throw new Exception('duplicate keys found: ' . implode(',', array_keys($duplicates)));
}
# Recreate the array with lower-case keys
$array = array_combine($lowerCaseKeys, array_values($array));

EDIT Or the pragmatic approach (should be much faster):

$lowerCaseKeyArray = array_change_key_case($array);
if (count($lowerCaseKeyArray) !== count($array)) {
    # You can extract the duplicate keys here as above, if you like
    throw new Exception('duplicate keys found!');
}
soulmerge
  • 73,842
  • 19
  • 118
  • 155
  • 1
    Yeah, builtins are almost always going to be faster. When it's Compiled C vs. PHP Opt-Code, guess who wins :) – Alana Storm Jul 22 '09 at 07:16
3

You could use array_change_key_case(). This can cause array keys to be overwritten, so you would want to compare the array sizes using count() before and after you do the key case change. Because of the counts(), I'm not sure if this method would give you better performance or not, you'd have to benchmark it.

$new = array_change_key_case($old, CASE_LOWER);
if (count($new) < count($old)) {
    throw new Exception("Duplicate key encountered.");
}
zombat
  • 92,731
  • 24
  • 156
  • 164
0
foreach(array_keys($old) as $key) {
  $lower = strtolower($key);
  //if key is already lower case, do nothing
  if($key == $lower)
    continue;
  $value = $old[$key];
  unset($old[$key]);
  $old[$lower] = $value;
}
Frank Farmer
  • 38,246
  • 12
  • 71
  • 89
0

Support for multidimensional arrays, inspired from this PHP manual comment:

function array_change_key_case_recursive($input, $case = CASE_LOWER)
{
    if (!is_array($input))
    {
        trigger_error("Invalid input array '{$array}'", E_USER_NOTICE);
        return false;
    }

    if (!in_array($case, array(CASE_UPPER, CASE_LOWER)))
    {
        trigger_error("Case parameter '{$case}' is invalid.", E_USER_NOTICE);
        return false;
    }

    $input = array_change_key_case($input, $case);

    foreach($input as $key => $array)
        if(is_array($array))
            $input[$key] = array_change_key_case_recursive($array, $case);

    return $input;
}

For better performance, it uses the native array_change_key_case() PHP function.

Maxime Pacary
  • 22,336
  • 11
  • 85
  • 113