不区分大小写的字典搜索?

时间:2010-07-21 05:23:19

标签: python dictionary

我可以使用map来用Python实现不区分大小写的列表搜索。

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

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

我怎么能用字典做同样的事情?

我尝试了以下代码,但是ap有['a','b','c']的列表,而不是不区分大小写的字典。

a = {'a':1, 'B':2, 'c':3}
ap = map(string.lower, a)

6 个答案:

答案 0 :(得分:36)

请注意,无论使用什么意思,使字典不区分大小写,都可能会丢失信息:例如,您如何“不区分大小写”{'a': 23, 'A': 45} ?!如果你所关心的只是一个密钥在dict中的位置(即,不关心它对应的是什么值),那么改为set - 即。

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

(在每个版本的Python中,或者{k.lower() for k in thedict}如果您对仅在Python 2.7或更高版本中工作的代码感到满意,为了一些纯粹的装饰性语法糖;-),并检查{{1 }}

或者,您可以创建一个包装类,例如,可能是只读的...:

if k.lower() in theset: ...

这将保留(实际上不改变原始字典,因此,如果需要的话,仍然可以为其检索所有精确信息)任意一个可能多个值,用于将“折叠”成单个密钥的密钥由于不区分大小写,并提供所有字典的只读方法(仅限字符串键)和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()) 方法返回用于任何给定字符串键的实际案例组合(如果没有案例,则返回actual_key_case - 给定字符串键的转换与字典中的任何键匹配。)

答案 1 :(得分:14)

使用dict理解(Python2.7 +)

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

如果你的python对于dict理解来说太旧了

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

然后使用键的小写版本

查找值
value = a_lower[key.lower()]

答案 2 :(得分:11)

通过以下方式开始使用不区分大小写的字典:

from requests import CaseInsensitiveDict

或者如果你想看代码:

class CaseInsensitiveDict(dict):

    """Basic case insensitive dict with strings only keys."""

    proxy = {}

    def __init__(self, data):
        self.proxy = dict((k.lower(), k) for k in data)
        for k in data:
            self[k] = data[k]

    def __contains__(self, k):
        return k.lower() in self.proxy

    def __delitem__(self, k):
        key = self.proxy[k.lower()]
        super(CaseInsensitiveDict, self).__delitem__(key)
        del self.proxy[k.lower()]

    def __getitem__(self, k):
        key = self.proxy[k.lower()]
        return super(CaseInsensitiveDict, self).__getitem__(key)

    def get(self, k, default=None):
        return self[k] if k in self else default

    def __setitem__(self, k, v):
        super(CaseInsensitiveDict, self).__setitem__(k, v)
        self.proxy[k.lower()] = k

答案 3 :(得分:5)

dict(zip(map(string.lower,a.keys()),a.values()))

会做你想要的。

map(function,iterable)在iterable上工作;字典的可迭代是键列表。

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

zip将键和值重新组合成对,但作为一系列元组。 dict将元组转换回dict。

您也可以执行类似

的操作
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}

或者,更有趣......

dict(map(lambda (key, value):(string.lower(key),value),a.items()))

答案 4 :(得分:3)

如果您不经常需要查找,则可以使用此功能而不会浪费其他字典副本的空间。虽然每次都必须检查所有键,但速度很慢。

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'

答案 5 :(得分:1)

只想添加__setitem__,弹出Alex Martelli的答案:

from collections import Mapping

class CaseInsensitiveDict(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 __setitem__(self, k, v):
        self._d[k] = v
        self._s[k.lower()] = k
    def pop(self, k):
        k0 = self._s.pop(k.lower())
        return self._d.pop(k0)
    def actual_key_case(self, k):
        return self._s.get(k.lower())