2015-09-10 3 views
3

У меня есть установка ДИКТ так:элементов фильтра по значению в Словаре

deck = [{ 
     'name': 'drew', 
     'lvl': 23, 
     'items': ['sword', 'axe', 'mana_potion']}, 
     { 
     'name': 'john', 
     'lvl': 23, 
     'items': ['sword', 'mace', 'health_potion']}] 

Это простой пример того, что он выглядит, мне нужен способ фильтрации (копировать только {символов}), что соответствуют определенным значениям, например, я хочу, чтобы были только персонажи уровня 23, или которые несут меч.

Я смотрел на делать что-то вроде этого:

filtered = filter_deck(deck, 'mace') 

def filter_deck(self, deck, filt): 
     return [{k:v for (k,v) in deck.items() if filt in k}] 

и возвращение:

filtered = [{ 
      'name': 'john', 
      'lvl': 23, 
      'items': ['sword', 'mace', 'health_potion']}] 

Я не знаю, как фильтровать либо конкретный элемент, как к: V или к: [v1 , v2, v3], когда я не знаю, является ли это одним значением, или списком значений, или как фильтровать несколько значений.

Я не уверен, как я могу фильтровать символы с несколькими ключами. Скажите, что я хочу сортировать персонажей, которые являются lvl 23, или иметь предметы ['sword'] или предметы ['mace']. Как бы я его сортировал в некотором роде filter_cards(deck, ['lvl'=23, 'items'=['sword','mace'])

Так что, если какой-либо персонаж является lvl 23 или несет булаву или меч, они находятся в этом списке.

+0

Вам нужен весь словарь, где слово находится в значении 'items' справа? –

+0

Является ли это 'filter in v' вместо' filter in k' в вашем понимании dict? – xtreak

+0

Для простых значений вы можете попробовать слово 'in'. Если вы хотите знать, что один элемент в списке A присутствует в списке B. Вы можете использовать наборы. 'A = ['mouse', 'mace']' и 'B = ['sword', 'mace']'. Вы можете проверить, носит ли A буйвол или меч «set (A) & set (B)». Кроме того, я считаю, что сам в функции фильтрованной палубы не нужен[email protected] – xtreak

ответ

2

Ваш deck - это список (словарей), он не имеет .items(). поэтому попытка сделать - deck.items() потерпит неудачу.

Также синтаксис -

filter_cards(deck, ['lvl'=23, 'items'=['sword','mace']) 

недействителен, Вы должны использовать словарь в качестве второго элемента. Пример -

filter_cards(deck, {'lvl':23, 'items':['sword','mace']}) 

Вы должны использовать filter() встроенной функции с функцией, которая возвращает истину, если словарь содержит одно из значений. Пример -

def filter_func(dic, filterdic): 
    for k,v in filterdic.items(): 
     if k == 'items': 
      if any(elemv in dic[k] for elemv in v): 
       return True 
     elif v == dic[k]: 
      return True 
    return False 

def filter_cards(deck, filterdic): 
    return list(filter(lambda dic, filterdic=filterdic: filter_func(dic, filterdic) , deck)) 

Demo -

>>> deck = [{ 
...   'name': 'drew', 
...   'lvl': 23, 
...   'items': ['sword', 'axe', 'mana_potion']},{ 
...   'name': 'john', 
...   'lvl': 23, 
...   'items': ['sword', 'mace', 'health_potion']},{ 
...   'name': 'somethingelse', 
...   'lvl': 10, 
...   'items': ['health_potion']}] 
>>> 
>>> 
>>> filter_cards(deck, {'lvl':23, 'items':['sword','mace']}) 
[{'lvl': 23, 'items': ['sword', 'axe', 'mana_potion'], 'name': 'drew'}, {'lvl': 23, 'items': ['sword', 'mace', 'health_potion'], 'name': 'john'}] 
+0

Работает отлично! – Drew

1

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

filter(lambda x: 'mace' in x['items'], deck) 
filter(lambda x: x['lvl'] == 23 or any(i in x['items'] for i in ['sword', 'mace']), deck) 

т.д. Эти генераторы возвратный фильтр поэтому, если вы хотите распечатать их, включите их в список:

>>> list(filter(lambda x: x['lvl'] == 23 or any(i in x['items'] for i in ['sword', 'mace']), deck)) 
[{'items': ['sword', 'axe', 'mana_potion'], 'lvl': 23, 'name': 'drew'}, 
{'items': ['sword', 'mace', 'health_potion'], 'lvl': 23, 'name': 'john'}] 

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

>>> def lvl_sword_mace(x): 
...  return x['lvl'] == 23 or any(i in x['items'] for i in ['sword', 'mace']) 
... 
>>> list(filter(lvl_sword_mace, deck)) 
[{'items': ['sword', 'axe', 'mana_potion'], 'lvl': 23, 'name': 'drew'}, 
{'items': ['sword', 'mace', 'health_potion'], 'lvl': 23, 'name': 'john'}] 
0

Правильный способ фильтрации Dict, используя список понимание является запрашивая поле, которое вы хотите фильтровать против. key in dictionary эквивалентен key in dictionary.keys() в python2.Правильный синтаксис выглядит следующим образом:

[card for card in deck if 'mace' in card['items']] 

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

filter(lambda card: 'mace' in card['items'], deck) 

Если вы хотите отфильтровать от нескольких значений, вы можете цепи тесты с использованием and и or захватить Подмножество вашу потребность :

[card for card in deck if 'mace' in card['items'] and card['lvl'] == 23] 

Если фильтр становится больше, создайте функцию.

В этом случае filter не дает больше значения, чем количество включений. Пояснения к списку легче читать, когда они короткие, больше, чем их счетчик filter. А для комплекса для фильтрации случаях требуется функция для чтения.

0

deck не является диктофоном, а списком диктофонов, поэтому я предполагаю, что ваш поиск должен вернуть список диктонов, соответствующих вашим критериям поиска.

Есть два случая, которые следует учитывать: во-первых, когда вы хотите сопоставить определенное значение для определенного ключа - что вам понадобится для таких атрибутов, как lvl и name. Во-вторых, вы ищете значение в списке, хранящемся в атрибуте. Вам понадобится, например, чтобы узнать, несет ли игрок определенный предмет.

Это будет иметь смысл для вас на самом деле знают разницу между этим - предположительно items всегда список, и lvl всегда является целым? - и вы можете зарегистрировать типы в подсобном Словаре так:

is_list = {'name': False, 
      'lvl': False, 
      'items': True} 

Вы могли бы сделать то же самое решение динамически, если вы должны были путем изучения type() каких-либо пункта, но это не очень хорошая практика, чтобы иметь переменные данные так как это несколько усложняет вашу логику. Поскольку вы добавляете аргумент self к своей функции, я предполагаю, что это метод, но это не имеет отношения к вопросу.

Учитывая наличие is_list вашей логики может определить test_card функции, которая возвращает значение ИСТИНЫ, если карта соответствует вашим критериям, и filter_deck функцию, которая перебирает палубу возвращающихся только те карты, которые соответствуют по крайней мере одному из критериев. Логика будет выглядеть примерно так:

deck = [{ 
     'name': 'drew', 
     'lvl': 23, 
     'items': ['sword', 'axe', 'mana_potion']}, 
     {'name': 'john', 
     'lvl': 23, 
     'items': ['sword', 'mace', 'health_potion']}, 
     {'name': 'somethingelse', 
     'lvl': 10, 
      'items': ['health_potion']}] 

is_list = {'name': False, 
      'lvl': False, 
      'items': True} 

def test_card(card, name, values): 
    if is_list[name]: # values is a list 
     return any(value in card[name] for value in values) 
    else:    # values is a single value 
     return card[name] == values 

def filter_deck(deck, **filters): # filters is a dict of keyword args 
    r = [] 
    for d in deck: 
     #print "Filtering", d, "on", filters 
     if any(test_card(d, n, v) for n, v in filters.items()): 
      r.append(d) 
    return r 

print filter_deck(deck, name="john") 
print filter_deck(deck, name="drew", lvl=10) 

, который выводит

[{'lvl': 23, 'name': 'john', 'items': ['sword', 'mace', 'health_potion']}] 
[{'lvl': 23, 'name': 'drew', 'items': ['sword', 'axe', 'mana_potion']}, {'lvl': 10, 'name': 'somethingelse', 'items': ['health_potion']}] 

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

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