views:

189

answers:

4

I can use map to implement the case insensitive list search with Python.

a = ['xyz', 'wMa', 'Pma'];

b = map(string.lower, a)
if 'Xyz'.lower() in b:
    print 'yes'

How can I do the same thing with dictionary?

I tried the following code, but ap has the list of ['a','b','c'], not the case insensitive dictionary.

a = {'a':1, 'B':2, 'c':3}
ap = map(string.lower, a)
+2  A: 
dict(zip(map(string.lower,a.keys()),a.values()))

will do what you're looking for.

map(function,iterable) works over the iterable; and iterable of the dictionary is the list of keys.

a = {'a': 1, 'c': 3, 'B': 2}
for i in a:
 print a
# returns a c B

zip brings together the keys and values back into pairs, but as a series of tuples. dict converts the tuples back into a dict.

You could also do something like

def myfunc(t):
 return (string.lower(t[0]),t[1])

map(myfunc,a.items())
# returns [('a', 1), ('c', 3), ('b', 2)
dict(map(myfunc,a.items()))
# returns {'a': 1, 'c': 3, 'b': 2}

Or, even more fun...

dict(map(lambda (key, value):(string.lower(key),value),a.items()))
Rizwan Kassim
+1  A: 

Using dict comprehensions (Python2.7+)

a_lower = {k.lower():v for k,v in a.items()}

If your python is too old for dict comprehensions

a_lower = dict((k.lower(),v) for k,v in a.items())

then look up the value with the lowercase version of the key

value = a_lower[key.lower()]
gnibbler
+4  A: 

Note that making a dictionary case-insensitive, by whatever mean, may well lose information: for example, how would you "case-insensitivize" {'a': 23, 'A': 45}?! If all you care is where a key is in the dict or not (i.e., don't care about what value corresponds to it), then make a set instead -- i.e.

theset = set(k.lower() for k in thedict)

(in every version of Python, or {k.lower() for k in thedict} if you're happy with your code working only in Python 2.7 or later for the sake of some purely decorative syntax sugar;-), and check with if k.lower() in theset: ....

Or, you could make a wrapper class, e.g., maybe a read-only one...:

import collections

class CaseInsensitiveDict(collections.Mapping):
    def __init__(self, d):
        self._d = d
        self._s = dict((k.lower(), k) for k in d)
    def __contains__(self, k):
        return k.lower() in self._s
    def __len__(self):
        return len(self._s)
    def __iter__(self):
        return iter(self._s)
    def __getitem__(self, k):
        return self._d[self_s[k.lower()]]
    def actual_key_case(self, k):
        return self._s.get(k.lower())

This will keep (without actually altering the original dictionary, so all precise information can still be retrieve for it, if and when needed) an arbitrary one of possibly-multiple values for keys that "collapse" into a single key due to the case-insensitiveness, and offer all read-only methods of dictionaries (with string keys, only) plus an actual_key_case method returning the actual case mix used for any given string key (or None if no case-alteration of that given string key matches any key in the dictionary).

Alex Martelli
A: 

If you are not needing the lookup very often you can use this function without wasting space for other copy of dictionary. It is slow though as all keys must be checked against every time.

a = {'xyz':2, 'wMa':8, 'Pma':9}

## if you do not use many times and/or the dict is very big

def case_insensitive_key(a,k):
    k = k.lower()
    return [a[key] for key in a if key.lower() == k]

print 'yes' if case_insensitive_key(a,'Xyz') else 'no'
Tony Veijalainen