2012-02-20 3 views
2

У меня есть информация о связке разных предметов. Каждый элемент имеет свой словарь, заполненный информацией об этом элементе, и у меня есть более крупный словарь, в котором хранится каждый элемент. Однако у меня нет одинаковой информации для каждого элемента. Например, скажем, мои вещи - фрукты. Тогда структура выглядит следующим образом:найти все словари, у которых есть неопределенное количество определенных ключей

fruit = {} 
fruit['apple'] = {'color': 'red', 'origin': 'Washington'} 
fruit['banana'] = {'color': 'yellow'} 
fruit['orange'] = {'color': 'orange', 'origin': 'Florida'} 

Если я хочу, чтобы найти происхождение каждого плода, для которых он был определен, я делаю следующее:

fruits, origins = zip(* [(f, fruit[f]['origin']) for f in fruit.keys() if 'origin' in fruit[f]]) 

Это работает отлично. Он начинает становиться уродливым, когда я хочу найти каждый плод, который имеет как цвет, так и происхождение.

fruits, origins, colors = zip(* [(f, fruit[f]['origin'], fruit[f]['color']) for f in fruit.keys() if 'origin' in fruit[f] and 'color' in fruit[f]]) 

То, что я хотел бы сделать, это быть в состоянии написать общую функцию, которая будет выполнять это действие для любого количества указанных ключей. То есть я мог бы вызвать некоторую функцию под названием «определенный», в которой будет использоваться словарь словарей, ключ или список ключей в подъязыкальном словаре и вернуть все суб-словари, которые имеют определения для каждого из этих ключей, а также значения для каждого ключа.

fruits, origins = defined(fruit, ['origin']) 
fruits, origins, colors = defined(fruit, ['origin', 'color']) 

Я посмотрел на различных существующих потоков с вопросами о получении пар ключ/значение из или в словарях, но я все, что выглядит право не найдено. Есть ли простой способ обобщить это?

Или, если люди также хотят сказать мне, что я должен организовать свои данные совершенно по-другому, я бы тоже приветствовал это. Сначала я остановился на словаре словарей из-за широкого спектра информации, доступной для каждого элемента. Например, некоторые суб-словари содержат десятки записей с информацией, а некоторые элементы имеют только несколько записей (т. Е. Словарь «яблочный» содержит много информации, но я не так много хранил в «kumquat»).

ответ

4

Вы можете обобщать извлечение значения списка осмыслению и and последовательности по all:

def defined(dct, keys): 
    return zip(*[([k] + [v[m] for m in keys]) 
       for k, v in dct.iteritems() 
       if all(m in v for m in keys)]) 
+0

Отлично, это сработало так, как я надеялся. Спасибо! – jdmcbr

2

Вот функция, которая возвращает данные немного по-другому, чем предложено вашими вызовами: возвращает итератор, который выполняет итерацию по всем словарным записям, содержащим все необходимые поля.

def defined(fruits, attr_names): 
    getter = operator.itemgetter(*attr_names) 
    for f, d in fruit.iteritems(): 
     try: 
      attrs = getter(d) 
     except KeyError: 
      continue 
     else: 
      yield (f,) + attrs 

Единственное в реализации, что может быть стоит упомянуть operator.itemgetter(). Вызов как

operator.itemgetter(['origin', 'color']) 

возвращает функцию, которая, примененная к словарю, будет возвращать значения для ключей 'origin' и 'color' как кортеж. Если один из ключей не может быть обращен вверх, словарь будет вызывать KeyError, как обычно.

Вы можете использовать zip() на возвращенном итераторе, чтобы использовать эту функцию в том, как вы предложили:

fruits, origins, colors = zip(*defined(fruit, ['origin', 'color'])) 
+0

Спасибо! Это работало на примере игрушек, который я дал. По какой-то причине я не могу заставить ее работать для моей реальной проблемы, но я буду играть с этим дальше и попытаюсь понять, что именно это делает. – jdmcbr

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