Добавить значение уже существующего ключа в dict в виде контейнера в Python - PullRequest
1 голос
/ 29 мая 2020

Есть ли какая-нибудь встроенная функция, которая будет делать следующее?

dictionary = {‘a’:1, ‘b’:2, ‘c’:3}

dictionary.update(c=10)

# what happens
dictionary  ---- {‘a’:1, ‘b’:2, ‘c’:10}

# what I want to happen:
dictionary  ---- {‘a’:1, ‘b’:2, ‘c’:(3, 10)}

По умолчанию, если ключи совпадают, более поздний ключ будет иметь приоритет над предыдущим. Если ключ уже присутствует в dict, значение новой пары ключ: значение будет добавлено к уже существующему значению в форме контейнера, такого как кортеж, список или набор.

Я могу написать помощника функция для этого, но я считаю, что это должно быть что-то встроенное для этого.

Ответы [ 4 ]

2 голосов
/ 29 мая 2020

Вы можете переписать функцию обновления, создав новый класс:

В Python bulitins.py:

    def update(self, E=None, **F): # known special case of dict.update
        """
        D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
        If E is present and has a .keys() method, then does:  for k in E: D[k] = E[k]
        If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
        In either case, this is followed by: for k in F:  D[k] = F[k]
        """
        pass

Итак, я пишу это (Наследовать от UserDict, рекомендуется by @timgeb):

from collections import UserDict


class CustomDict(UserDict):
    def __init__(self):
        super().__init__()

    def update(self, E=None, **F) -> None:
        if E:
            if isinstance(E, dict):
                for k in E:
                    self[k] = E[k]
            else:
                for k, v in E:
                    self[k] = v
        else:
            if isinstance(F, dict):
                for key in F:
                    if isinstance(self[key], list):
                        self[key].append(F[key])
                    else:
                        self[key] = [self[key], F[key]]


dictionary = CustomDict()
dictionary.update({'a': 1, 'b': 2, 'c': 3})
print(dictionary)
dictionary.update(a=3)
print(dictionary)
dictionary.update(a=4)
print(dictionary)

Результат:

{'a': 1, 'b': 2, 'c': 3}
{'a': [1, 3], 'b': 2, 'c': 3}
{'a': [1, 3, 4], 'b': 2, 'c': 3}

Может быть, в моем коде есть несколько ошибок logi c, но обращаем ваше внимание.

2 голосов
/ 29 мая 2020

Вы можете это сделать

from collections import defaultdict
d = defaultdict(list)
d["a"].append(1)
d["b"].append(2)
d["c"].append(3)
d["c"].append(10)

print(d)

Результат

defaultdict(list, {'a': [1], 'b': [2], 'c': [3, 10]})
2 голосов
/ 29 мая 2020

Ваше желаемое решение не очень элегантно, поэтому я собираюсь предложить альтернативное.

  1. Кортежи неизменяемы. Вместо этого давайте использовать списки, потому что мы можем легко добавлять к ним.
  2. Тип данных значений должен быть согласованным. В любом случае используйте списки, даже для отдельных значений.
  3. Давайте использовать defaultdict, чтобы нам не приходилось инициализировать списки вручную.

Объединение:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for v, k in enumerate('abc', 1):
...     d[k].append(v)    
...     
>>> d
defaultdict(<class 'list'>, {'a': [1], 'b': [2], 'c': [3]})
>>> d['c'].append(10)
>>> d
defaultdict(<class 'list'>, {'a': [1], 'b': [2], 'c': [3, 10]})
0 голосов
/ 29 мая 2020

Возможно, вы могли бы использовать что-то вроде:

dictionary = {'a':1, 'b':2, 'c':3}
dictionary.update({'c': 10 if not dictionary.get('c') else tuple([dictionary['c'],] + [10,])})
# {'a': 1, 'b': 2, 'c': (3, 10)}

Но, вероятно, его следует обернуть в функцию, чтобы все было чисто. Общий шаблон будет (я полагаю, на основе вашего вопроса):

dict = {...}
if 'a' not in dict:
    do_this() # just add it to the dict?
else:
    do_that() # build a tuple or list?

В вашем приведенном выше вопросе вы смешиваете типы - я не уверен, хотите ли вы этого, более pythoni c подход может заключаться в том, чтобы иметь все значения в виде списка и использовать defaultdict.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...