Отображение значений в словаре python

Учитывая словарь { k1: v1, k2: v2 ... }, я хочу получить { k1: f(v1), k2: f(v2) ... } при условии, что передаю функцию f.

Есть ли такая встроенная функция? Или мне нужно делать

dict([(k, f(v)) for (k, v) in my_dictionary.iteritems()])

В идеале я просто напишу

my_dictionary.map_values(f)

или

my_dictionary.mutate_values_with(f)

То есть, для меня не имеет значения, если исходный словарь мутирован или создается копия.

Ответ 1

Там нет такой функции; самый простой способ сделать это состоит в том, чтобы использовать сложное понимание:

my_dictionary = {k: f(v) for k, v in my_dictionary.items()}

В python 2.7 используйте метод .iteritems() вместо .items() для экономии памяти. Синтаксис распознавания текста не был введен до Python 2.7.

Обратите внимание, что в списках такого метода тоже нет; Вы должны использовать понимание списка или функцию map().

Таким образом, вы также можете использовать функцию map() для обработки вашего dict:

my_dictionary = dict(map(lambda kv: (kv[0], f(kv[1])), my_dictionary.iteritems()))

но это не так читабельно, правда.

Ответ 2

Эти инструменты отлично подходят для такой простой, но повторяющейся логики.

http://toolz.readthedocs.org/en/latest/api.html#toolz.dicttoolz.valmap

Получает вас там, где вы хотите быть.

import toolz
def f(x):
  return x+1

toolz.valmap(f, my_list)

Ответ 3

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

def mutate_dict(f,d):
    for k, v in d.iteritems():
        d[k] = f(v)

my_dictionary = {'a':1, 'b':2}
mutate_dict(lambda x: x+1, my_dictionary)

приводит к my_dictionary, содержащему:

{'a': 2, 'b': 3}

Ответ 4

В то время как мой первоначальный ответ пропустил эту точку (пытаясь решить эту проблему с помощью решения Доступ к ключу в factory defaultdict), я переработал его предложить реальное решение данного вопроса.

Вот он:

class walkableDict(dict):
  def walk(self, callback):
    try:
      for key in self:
        self[key] = callback(self[key])
    except TypeError:
      return False
    return True

Использование:

>>> d = walkableDict({ k1: v1, k2: v2 ... })
>>> d.walk(f)

Идея состоит в том, чтобы подклассифицировать исходный dict, чтобы дать ему желаемую функциональность: "отображение" функции по всем значениям.

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

Конечно, не стесняйтесь называть класс и функцию так, как вы хотите (имя, выбранное в этом ответе, вдохновлено PHP array_walk()).

Примечание. Для функциональности не требуются ни теги try - except, ни инструкции return, они там для дальнейшей имитации поведения PHP array_walk.

Ответ 5

Из-за PEP-0469, который переименовал iteritems() в items(), и PEP-3113, который удалил распаковку параметров Tuple, в Python 3.x вы должны написать Martijn Pieters ♦ ответ такой:

my_dictionary = dict(map(lambda item: (item[0], f(item[1])), my_dictionary.items()))

Ответ 6

Просто наткнулся на этот вариант использования. Я реализовал gens answer, добавив рекурсивный подход для обработки значений, которые также являются dicts:

def mutate_dict_in_place(f, d):
    for k, v in d.iteritems():
        if isinstance(v, dict):
            mutate_dict_in_place(f, v)
        else:
            d[k] = f(v)

# Exemple handy usage
def utf8_everywhere(d):
    mutate_dict_in_place((
        lambda value:
            value.decode('utf-8')
            if isinstance(value, bytes)
            else value
        ),
        d
    )

my_dict = {'a': b'byte1', 'b': {'c': b'byte2', 'd': b'byte3'}}
utf8_everywhere(my_dict)
print(my_dict)

Это может быть полезно при работе с файлами json или yaml, которые кодируют строки как байты в Python 2

Ответ 7

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

rval = dict(map(lambda kv : (kv[0], ' '.join(kv[1])), rval.iteritems()))

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

rval = dict(map(lambda(k,v) : (k, ' '.join(v)), rval.iteritems()))