2015-04-28 2 views
3

У меня есть Dict(), как это так,Проверка multilpe ключей в Словаре

xyz = {"a":{"b":[1,2,3]}} 

Я хочу, чтобы проверить, если вложенная ДИКТ имеет ключ «б» или «в». я могу проверить один ключ, как,

>>> "b" in xyz.get("a",{}) 
True 

Ive пытался следующее,

>>> "b" or "c" in xyz.get("a",{}) 
'b' 

Но хотелось бы знать, могу ли я написать это заявление как для «б» и «в». Надеюсь, это имеет смысл.

+0

'или' не работает; это может быть наиболее часто задаваемый вопрос Python в StackOverflow. Вы можете просто сделать «b» в xyz.get («a», {}) или «c» в xyz.get («a», {}) '. – abarnert

ответ

2

or не работает так. (Это может быть наиболее часто задаваемый вопрос Python на StackOverflow, но, к сожалению, его очень сложно найти, если вы уже не знаете, в чем проблема ...) or просто принимает два булевых выражения и возвращает что-то правдоподобное, если любое из них правдиво. то, что вы просите, является ли "b" правдой (это), или "c" in xyz.get("a", {}) является правдивым (это может быть или не быть, но Python даже не нужно проверять), поэтому он возвращает вам "b", что является правдой.

Возможно, вы можете исправить это с помощью круглых скобок ("b" or "c") in xyz.get("a", {}), но это так же плохо. Сначала он будет оценивать ("b" or "c") и получить "b", тогда он проверяет, находится ли это в dict, игнорируя "c".

Причина, по которой эквивалентное предложение имеет смысл на английском языке, заключается в том, что вы неявно спрашиваете: «это b в dict или c в dict»; Python не позволит вам оставить это неявный, но вы всегда можете сделать это явно:

"b" in xyz.get("a", {}) or "c" in xyz.get("a", {})` 

Если вы хотите сделать больше, чем 2 из них (или, если они только известны динамически), то вы будете хотите использовать any и/или хранить xyz.get("a", {}) во временной переменной вместо повторения, как в ответе utdemir, или, может быть, даже лучше, используя набор, как в ответе Кастры.

+0

В этом случае это более быстрое решение! но для большего значения это не очень хороший выбор! – Kasramvd

+1

@ Kasra: Я не знаю, быстрее ли это. Я думаю, что это легче понять для новичков, что важно. Но с более чем 2 или 3 он становится очень неуклюжим, поэтому я сказал использовать одно из двух других решений в этом случае. – abarnert

5

any и генераторные выражения ваш друг:

>>> xyz = {"a":{"b":[1,2,3]}} 
>>> any(i in xyz.get("a",{}) for i in ["b", "c"]) 
True 
+2

Незначительная техническая точка: это не понимание списка, это выражение генератора (которое по-прежнему является своего рода пониманием, по крайней мере в 3.x, просто не таким же). – abarnert

+0

Вы правы, отредактированы. Спасибо. – utdemir

1

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

>>> bool({'b','c'}.intersection(xyz.get('a'))) 
True 

следующий тест показывает, что его более эффективным, чем any:

:~$ python -m timeit "xyz = {'a':{'b':[1,2,3]}};any(i in xyz.get('a',{}) for i in ['b', 'c'])" 
1000000 loops, best of 3: 0.932 usec per loop 

:~$ python -m timeit "xyz = {'a':{'b':[1,2,3]}};bool({'b','c'}.intersection(xyz.get('a')))" 
1000000 loops, best of 3: 0.649 usec per loop 

Но Ответ @ abarnert в этот случай является самым быстрым:

~$ python -m timeit "xyz = {'a':{'b':[1,2,3]}};'b' in xyz.get('a', {}) or 'c' in xyz.get('a', {})" 
1000000 loops, best of 3: 0.325 usec per loop 
+0

Думаю, вам нужно 'xyz.get ('a', {})', а не 'xyz ['a']'. Он не объясняет, почему в его вопросе, но, по-видимому, это по какой-то причине, так как ключ «а» не всегда существует. – abarnert

+0

Кроме того, вам не нужен вызов 'keys'; dict уже является Итерабельностью его ключей. – abarnert

+0

@abarnert Да, конечно, исправлено! – Kasramvd