php: Array keys case *insensitive* lookup?

PhpArrays

Php Problem Overview


$myArray = array ('SOmeKeyNAme' => 7);  

I want $myArray['somekeyname'] to return 7.
Is there a way to do this, without manipulating the array?

I don't create the array, an thus can not control it's keys

Php Solutions


Solution 1 - Php

Option 1 - change the way you create the array

You can't do this without either a linear search or altering the original array. The most efficient approach will be to use strtolower on keys when you insert AND when you lookup values.

 $myArray[strtolower('SOmeKeyNAme')]=7;

 if (isset($myArray[strtolower('SomekeyName')]))
 {

 }

If it's important to you to preserve the original case of the key, you could store it as a additional value for that key, e.g.

$myArray[strtolower('SOmeKeyNAme')]=array('SOmeKeyNAme', 7);

Option 2 - create a secondary mapping

As you updated the question to suggest this wouldn't be possible for you, how about you create an array providing a mapping between lowercased and case-sensitive versions?

$keys=array_keys($myArray);
$map=array();
foreach($keys as $key)
{
     $map[strtolower($key)]=$key;
}

Now you can use this to obtain the case-sensitive key from a lowercased one

$test='somekeyname';
if (isset($map[$test]))
{
     $value=$myArray[$map[$test]];
}

This avoids the need to create a full copy of the array with a lower-cased key, which is really the only other way to go about this.

Option 3 - Create a copy of the array

If making a full copy of the array isn't a concern, then you can use array_change_key_case to create a copy with lower cased keys.

$myCopy=array_change_key_case($myArray, CASE_LOWER);

Solution 2 - Php

I know this is an older question but the most elegant way to handle this problem is to use:

array_change_key_case($myArray); //second parameter is CASE_LOWER by default

In your example:

$myArray = array ('SOmeKeyNAme' => 7);
$myArray = array_change_key_case($myArray);

Afterwards $myArray will contain all lowercase keys:

echo $myArray['somekeyname'] will contain 7

Alternatively you can use:

array_change_key_case($myArray, CASE_UPPER);

Documentation be seen here: http://us3.php.net/manual/en/function.array-change-key-case.php

Solution 3 - Php

You could use ArrayAccess interface to create a class that works with array syntax.

Example

$lower_array_object = new CaseInsensitiveArray;
$lower_array_object["thisISaKEY"] = "value";
print $lower_array_object["THISisAkey"]; //prints "value"

or

$lower_array_object = new CaseInsensitiveArray(
    array( "SoMeThInG" => "anything", ... )
);
print $lower_array_object["something"]; //prints "anything"

Class

class CaseInsensitiveArray implements ArrayAccess
{
    private $_container = array();
    
    public function __construct( Array $initial_array = array() ) {
        $this->_container = array_map( "strtolower", $initial_array );
    }
    
    public function offsetSet($offset, $value) {
        if( is_string( $offset ) ) $offset = strtolower($offset);
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }
    
    public function offsetExists($offset) {
        if( is_string( $offset ) ) $offset = strtolower($offset);
        return isset($this->_container[$offset]);
    }
    
    public function offsetUnset($offset) {
        if( is_string( $offset ) ) $offset = strtolower($offset);
        unset($this->container[$offset]);
    }
    
    public function offsetGet($offset) {
        if( is_string( $offset ) ) $offset = strtolower($offset);
        return isset($this->container[$offset])
            ? $this->container[$offset]
            : null;
    }
}

Solution 4 - Php

A simple, but maybe expensive way, is to make a copy, then use array_change_key_case($array_copy, CASE_LOWER), and after that access array_copy['somekeyname']

Solution 5 - Php

I combined Paul Dixon's idea of creating a mapping for the keys and Kendall Hopkins' idea of using the ArrayAccess interface for retaining the familiar way of accessing a PHP array.

The result is a class that avoids copying the initial array and allows transparent case-insensitive access, while internally preserving the keys' case. Limitation: If case-insensitively equal keys (e.g. 'Foo' and 'foo') are contained in the initial array or are added dynamically, then latter entries will overwrite previous ones (rendering these inaccessible).

Admittedly, in many cases its (imo) much more straight-forward to just lowercase the keys by $lowercasedKeys = array_change_key_case($array, CASE_LOWER);, as suggested by Mikpa.

The CaseInsensitiveKeysArray class

class CaseInsensitiveKeysArray implements ArrayAccess 
{
    private $container = array();
    private $keysMap   = array();

    public function __construct(Array $initial_array = array()) 
    {
        $this->container = $initial_array;

        $keys = array_keys($this->container);
        foreach ($keys as $key) 
        {
            $this->addMappedKey($key);
        }
    }

    public function offsetSet($offset, $value) 
    {
        if (is_null($offset)) 
        {
            $this->container[] = $value;
        }
        else 
        {
            $this->container[$offset] = $value;
            $this->addMappedKey($offset);
        }
    }

    public function offsetExists($offset) 
    {
        if (is_string($offset)) 
        {
            return isset($this->keysMap[strtolower($offset)]);
        }
        else 
        {
            return isset($this->container[$offset]);
        }
    }

    public function offsetUnset($offset) 
    {
        if ($this->offsetExists($offset)) 
        {
            unset($this->container[$this->getMappedKey($offset)]);
            if (is_string($offset)) 
            {
                unset($this->keysMap[strtolower($offset)]);
            }
        }
    }

    public function offsetGet($offset) 
    {
        return $this->offsetExists($offset) ? 
               $this->container[$this->getMappedKey($offset)] : 
               null;
    }

    public function getInternalArray() 
    {
        return $this->container;
    }

    private function addMappedKey($key) 
    {
        if (is_string($key)) 
        {
            $this->keysMap[strtolower($key)] = $key;
        }
    }

    private function getMappedKey($key) 
    {
        if (is_string($key)) 
        {
            return $this->keysMap[strtolower($key)];
        }
        else 
        {
            return $key;
        }
    }
}

Solution 6 - Php

From the PHP site

function array_ikey_exists($key, $haystack){
	return array_key_exists(strtolower($key), array_change_key_case($haystack));	
}

Referance: http://us1.php.net/manual/en/function.array-key-exists.php#108226

Solution 7 - Php

I also needed a way to return (the first) case-insensitive key match. Here's what I came up with:

/**
 * Case-insensitive search for present array key
 * @param string $needle
 * @param array $haystack
 * @return string|bool The present key, or false
 */
function get_array_ikey($needle, $haystack) {
    foreach ($haystack as $key => $meh) {
        if (strtolower($needle) == strtolower($key)) {
            return (string) $key;
        }
    }
    return false;
}

So, to answer the original question:

$myArray = array('SOmeKeyNAme' => 7);
$test = 'somekeyname';
$key = get_array_ikey($test, $myArray);
if ($key !== false) {
    echo $myArray[$key];
}

Solution 8 - Php

You can lowercase your keys when assigning them to the array and also lowercase them when looking up the value.

Without modifying the array, but the whole data structure:

A really cumbersome way involves creating magic getter/setter methods, but would it really be worth the effort (note that the other methods have to be implemented too)?

<?php 

class CaseInsensitiveArray
{ 

  protected $m_values;

  public function __construct()
  {
    $this->m_values = array();
  } 
    
  public function __get($key)
  { 
    return array_key_exists($key, $this->m_values) ? $this->m_values[$key] : null;
  } 
      
  public function __set($key, $value)
  { 
    $this->m_attributes[$key] = $value;
  } 
} 

Solution 9 - Php

You could loop through the array manually and search for a match.

foreach( $myArray as $key => $value ) {
    if( strtolower( $key ) == 'somekeyname' ) {
        // match found, $value == $myArray[ 'SOmeKeyNAme' ]
    }
}

Solution 10 - Php

In my case I wanted an efficient workaround where my program was already creating the array using a foreach loop from customer data having unknown case, and I wanted to preserve the customer's case for later display in the program.

My solution was to create a separate array $CaseMap to map a given lowercase key to the mixedcase key used in the array (irrelevant code is omitted here):

$CaseMap=[];
foreach ($UserArray as $Key=>$Value)
	$CaseMap[strtolower($Key)]=$Key;

Then lookup is like this:

$Value=$UserArray[$CaseMap("key")];

and the memory overhead is just the $CaseMap array, which maps presumably short keys to short keys.

I'm not sure if PHP has a more efficient way to generate $CaseMap in the case where I'n not already using foreach.

Solution 11 - Php

I just had same problem and I could not change original array. I use few array functions for it.

Parameters

$search = "AbCd";
$array = array("AbcD"=>"11","Bb"=>"22");

Solution

$lower_search = strtolower($search);
$array_of_keys = array_map("strtolower",array_keys($array));
$idx = array_search($lower_search,$array_of_keys);
if($idx !== FALSE)
    echo array_values($array)[$idx];

Make it shorter

if(($idx=array_search(strtolower($search),array_map("strtolower",array_keys($array))))!==FALSE)
    echo array_values($array)[$idx];

Solution 12 - Php

I know this is old, but in case anyone else needs a quick easy way to do this without actually changing the original array:

function array_key_i($needle, $haystack){
  $key=array_search(strtolower($search), array_combine(array_keys($array),array_map('strtolower', array_keys($array))));
  return ($key!==false);
}

$array=array('TeSt1'=>'maybe');
$search='test1';

array_key_i($search, $array); // returns true

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionshealtielView Question on Stackoverflow
Solution 1 - PhpPaul DixonView Answer on Stackoverflow
Solution 2 - PhpShawnView Answer on Stackoverflow
Solution 3 - PhpKendall HopkinsView Answer on Stackoverflow
Solution 4 - PhpMikpaView Answer on Stackoverflow
Solution 5 - PhpargonymView Answer on Stackoverflow
Solution 6 - PhpZaki AzizView Answer on Stackoverflow
Solution 7 - PhpBitwise CreativeView Answer on Stackoverflow
Solution 8 - PhpicanhasserverView Answer on Stackoverflow
Solution 9 - PhpJJJView Answer on Stackoverflow
Solution 10 - PhpDavid SpectorView Answer on Stackoverflow
Solution 11 - PhpCN LeeView Answer on Stackoverflow
Solution 12 - PhpTreyView Answer on Stackoverflow