2010-07-21 2 views
19

Я могу использовать карту для реализации поиска без учета регистра с помощью 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) 
+0

Вы хотите, чтобы решения, Я использовал карту - вот как я прочитал вопрос в первый раз. –

+1

См. [PEP-455] (https://www.python.org/dev/peps/pep-0455/): это запланировано для включения стандартной библиотеки в Python 3.5 (как 'collections.TransformDict', если преобразование 'str.casefold' или аналогичный) –

+0

[PEP-455 был в конечном счете отклонен.] (https://www.python.org/dev/peps/pep-0455/#rejection) –

ответ

30

Обратите внимание, что делает словарь нечувствительно к регистру, каким бы то ни среднее, вполне может потерять информацию, например, как бы вы «регистру insensitivize "{'a': 23, 'A': 45}?! Если все, что вам все равно, где ключ находится в Словаре или нет (то есть, не заботятся о том, что значение соответствует ему), то сделать set вместо этого - т.е.

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

(в каждой версии Python , или {k.lower() for k in thedict}, если вы довольны тем, что ваш код работает только в Python 2.7 или более поздней версии ради какого-то чисто декоративного синтаксического сахара ;-), и проверьте с помощью 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, возвращающий фактическую комбинацию случаев, используемую для любого заданного строкового ключа (или None, если никакая модификация этого заданного строкового ключа не соответствует любому ключу в словаре).

+0

Очень приятно - это решило проблему, я был где API выполнял нечувствительный к регистру совпадение по запрашиваемому имени поля, но возвращал имя канонического поля, поэтому я бы попросил «письмо», но получил «электронную почту». Этот диктофон позволяет мне сопоставить это с именем поля, которое я просил. Результат! – metadaddy

+2

мелкий опечатка in __getitem __() способ. self._s вместо self_s. По-видимому, я не могу сделать редактирование 1 символа в SO (должно быть> = 6) !! – SteveJ

+1

Не совсем взамен замены словаря, см. Полный текст на http://stackoverflow.com/a/27890005/99834 – sorin

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

будет делать то, что вы ищете.

map (function, 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())) 
12

Использование 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()] 
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' 
1

Просто хотел добавить __setitem__, поп-музыки до Ответ Алекс Мартелли в:

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()) 
8

начать использовать реальный случай нечувствительным словаря через:

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 
+5

Это на самом деле в request.structures сейчас: http://docs.python-requests.org /en/v0.5.0/api/#structures – Gallaecio

Смежные вопросы