У Python есть словарь с одноименными ключами?

Мне нужно иметь словарь, который может иметь одинаковые имена для некоторых ключей и возвращать список значений при ссылке на ключ в этом случае. Например

print mydict['key'] [1,2,3,4,5,6] 

  • Как получить случайное значение в словаре python
  • Python json parser позволяет дублировать ключи
  • Google App Engine - Datastore get_or_insert key_name путаница
  • Будет ли диктовать Python с целыми числами в качестве ключей, естественно отсортированных?
  • python: объединить сортировку-функции-item itemterter и str.lower
  • return key по значению в словаре
  • Python json parser позволяет дублировать ключи
  • Безопасность потоков в словаре Python
  • Python: использование vars () для назначения строки переменной
  • Как поднять ошибку, если дублирует ключи в словаре
  • Сохранение записей словаря Python в том порядке, в котором они нажаты
  • Извлечение части данных из файла JSON с помощью python
  • 6 Solutions collect form web for “У Python есть словарь с одноименными ключами?”

    Для согласованности вы должны иметь ключи карты словаря для списков (или наборов) значений, из которых некоторые могут быть пустыми. Для этого есть приятная идиома:

     from collections import defaultdict d = defaultdict(set) d["key"].add(...) 

    ( defaultdict – это обычный словарь, но если отсутствует ключ, он вызывается аргументом, который вы передали, когда вы его создавали, и используете результат как значение по умолчанию. Таким образом, это автоматически создаст пустой набор значений, если вы попросите ключ, который еще не присутствует.)


    Если вам нужен объект, который больше похож на словарь (т. Е. Установить значение с помощью d["key"] = ... ), вы можете сделать следующее. Но это, вероятно, плохая идея, потому что она идет против обычного синтаксиса Python и, скорее всего, вернется и укусит вас позже. Особенно, если кто-то еще должен поддерживать ваш код.

     class Multidict(defaultdict): def __init__(self): super(Multidict, self).__init__(set) def __setitem__(self, key, value): self[key].add(value) 

    Я не тестировал это.

    Вы также можете попробовать paste.util.multidict.MultiDict

     $ easy_install Paste 

    Затем:

     from paste.util.multidict import MultiDict d = MultiDict() d.add('a', 1) d.add('a', 2) d.add('b', 3) d.mixed() >>> {'a': [1, 2], 'b': 3} d.getall('a') >>> [1, 2] d.getall('b') >>> [3] 

    Веб-структуры, такие как Pylons, используют эту библиотеку для обработки строковых / почтовых данных HTTP-запроса, которые могут иметь одноименные ключи.

    Вы можете использовать:

     myDict = {'key': []} 

    Затем во время выполнения:

     if newKey in myDict: myDict[newKey].append(value) else: myDict[newKey] = [value] Проточите if newKey in myDict: myDict[newKey].append(value) else: myDict[newKey] = [value] 

    Отредактировано в соответствии с комментарием Бена:

     myDict = {} myDict.setdefault(newKey, []).append(value) 

    Я не удовлетворен всеми предлагаемыми решениями, поэтому это мое решение. Это для Python 3. Код ниже.

    ПРИМЕРЫ

    (код ниже)

     >>> a = MultiDict({0: [0]}) >>> a MultiDict({0: [0]}) >>> a[0] = (1, 7) >>> a MultiDict({0: [1, 7]}) >>> a.add(0, 2) >>> a MultiDict({0: [1, 7, 2]}) >>> a.add(1, 2) >>> a MultiDict({0: [1, 7, 2], 1: [2]}) >>> a.getfirst(0) 1 >>> a.getfirst(3) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 61, in getfirst File "<stdin>", line 17, in __getitem__ KeyError: 3 >>> len(a) 2 >>> tuple(a.items()) ((0, [1, 7, 2]), (1, [2])) >>> tuple(a.values()) ([1, 7, 2], [2]) >>> a.get(0) [1, 7, 2] >>> tuple(a.multiitems()) ((0, 1), (0, 7), (0, 2), (1, 2)) >>> tuple(a.multikeys()) (0, 0, 0, 1) >>> tuple(a.multivalues()) (1, 7, 2, 2) >>> a.remove(0, 1) >>> a MultiDict({0: [7, 2], 1: [2]}) >>> a.remove(3, 5) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 53, in remove File "<stdin>", line 17, in __getitem__ KeyError: 3 >>> a.remove(0, 5) Traceback (most recent call last): File "<stdin>", line 53, in remove ValueError: list.remove(x): x not in list During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 56, in remove ValueError: No element with value 5 for key 0 >>> b = MultiDict({0: [7, 2], 1: [2]}) >>> b == a True >>> c = MultiDict(a) >>> c MultiDict({0: [7, 2], 1: [2]}) >>> d = MultiDict({0: 0}) Traceback (most recent call last): File "<stdin>", line 30, in __init__ TypeError: 'int' object is not iterable During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 33, in __init__ TypeError: Values must be iterables, found 'int' for key 0 >>> a.pop(0) [7, 2] >>> a MultiDict({1: [2]}) >>> c.popitem() (0, [7, 2]) >>> c.setdefault(0, [1]) [1] >>> c MultiDict({0: [1], 1: [2]}) >>> c.setdefault(0, [2]) [1] >>> c MultiDict({0: [1], 1: [2]}) >>> c.setdefault(3) [] >>> c MultiDict({0: [1], 1: [2], 3: []}) >>> c.getfirst(3) Traceback (most recent call last): File "<stdin>", line 61, in getfirst IndexError: list index out of range During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 63, in getfirst IndexError: No values in key 3 >>> c.clear() >>> c MultiDict({}) >>> c.update(b) >>> c MultiDict({0: [7, 2], 1: [2]}) >>> d = c.copy() >>> d == c True >>> id(d) == id(c) False >>> MultiDict.fromkeys((0, 1), [5]) MultiDict({0: [5], 1: [5]}) >>> MultiDict.fromkeys((0, 1)) MultiDict({0: [], 1: []}) 

    КОД

     from collections.abc import MutableMapping class MultiDict(MutableMapping): @classmethod def fromkeys(cls, seq, value=None, *args, **kwargs): if value is None: v = [] else: v = value return MultiDict(dict.fromkeys(seq, v, *args, **kwargs)) def __setitem__(self, k, v): self._dict[k] = list(v) def __getitem__(self, k): return self._dict[k] def __iter__(self): for k in self._dict: yield k def __init__(self, *args, **kwargs): self._dict = dict(*args, **kwargs) for k, v in self._dict.items(): try: self._dict[k] = list(v) except TypeError: err_str = "Values must be iterables, found '{t}' for key {k}" raise TypeError(err_str.format(k=k, t=type(v).__name__)) def __delitem__(self, k): del self._dict[k] def __len__(self): return len(self._dict) def add(self, k, v): if not k in self: self[k] = [] self[k].append(v) def remove(self, k, v): try: self[k].remove(v) except ValueError: err_str = "No element with value {v} for key {k}" raise ValueError(err_str.format(v=v, k=k)) def getfirst(self, k): try: res = self[k][0] except IndexError: raise IndexError("No values in key {k}".format(k=k)) return self[k][0] def multiitems(self): for k, v in self.items(): for vv in v: yield (k, vv) def multikeys(self): for k, v in self.items(): for vv in v: yield k def multivalues(self): for v in self.values(): for vv in v: yield vv def setdefault(self, k, default=None): if default is None: def_val = [] else: def_val = default if k not in self: self[k] = def_val return self[k] def copy(self): return MultiDict(self) def __repr__(self): body_str = "" for k, v in self.items(): body_str += "{k}: {v}, ".format(k=repr(k), v=repr(v)) if body_str: body_str_true = body_str[:-2] else: body_str_true = body_str return "MultiDict({{{body}}})".format(body=body_str_true) 

    НЕКОТОРЫЕ ПЕРВОЕ ОБЪЯСНЕНИЕ

    Для простоты конструктор такой же, как dict . Все значения, переданные конструктору или назначаемые непосредственно ключу, должны быть итерабельными.

    Все значения моего MultiDict являются списками, даже если значение только одно. Это делается для того, чтобы избежать путаницы.

    Я также добавил метод удаления для удаления одной записи из MultiDict . Кроме того, я добавил многоэлементы, которые обрабатывают пару (ключ, значение) по всем значениям словаря. multikeys и multivalues схожи.

    АЛЬТЕРНАТИВЫ

    Вы также можете использовать aiohttp , WebOp или Werkzeug- реализации MultiDict.

     def toMultiDict(items): def insertMulti(d, kv): k, v = kv d.setdefault(k, []).append(v) return d return reduce(insertMulti, [{}] + items) 

    должен создать dict из ключа в список значений:

     In [28]: toMultiDict(zip([1,2,1], [4,5,6])) Out[28]: {1: [4, 6], 2: [5]} 

    Я не мог вставить insertMulti в лямбду, потому что лямбда должна снова вернуть dict.

    Это идеальное место для использования объекта defaultdict из библиотеки коллекций

     from collections import defaultdict mydict = defaultdict(set) mydict['key'] += set([1,2,3,4]) mydict['key'] += set([4,5,6]) print(mydict['key']) 

    возвращает [1,2,3,4,5,6]

    В случае ссылки на ключ, который не был неявно назначен, возвращается пустой набор.

     print(mydict['bad_key']) 

    возвращает []

    Использование setdefault в dict из стандартной библиотеки потребует значительного изменения вашего синтаксиса при назначении значений и может стать довольно беспорядочным. Я никогда не использовал Multidict, но он также выглядит значительным изменением в способах создания заданий. Используя этот метод, вы просто предполагаете, что уже может быть значение, связанное с этим ключом в словаре, и слегка изменить ваш оператор присваивания, используя оператор «+ =» при назначении значений ключа.

    FYI. Я большой поклонник использования NoneType в качестве значения по умолчанию, которое приводит к любому доступу к недопустимому ключу, возвращающему None. В большинстве случаев это ведет себя правильно, включая итерационные и json-дампы, но для вашей конкретной потребности по умолчанию должен быть установлен тип, если вы не хотите включать дубликаты значений, хранящихся в ключе. Затем используйте список . Фактически, в любое время, когда у вас есть гомогенный словарь, значение по умолчанию должно быть такого типа.

     mydict = defaultdict(lambda: None) 
    Python - лучший язык программирования в мире.