2016-06-12 12 views
4

辞書dctがあります。対応するキーが指定されたリストlstに存在すれば、それぞれの値を合計したいと思っています。Pythonジェネレータ式内の値をフィルタリングする

私がこれまで使っていたコードは次のとおりです。私は、リストからキーが辞書の中に発見されていない場合にはKeyErrorを処理したいと思います上記のジェネレータ式で

sum(dct[k] for k in lst) 

。私はtry - exceptのアプローチを実装する方法や、このジェネレータの表現の中でif - elseのアプローチを(構文的に)実装する方法を見つけることができないようです。

リスト内のキーが辞書内に見つからない場合は、他の値を取得する必要があります。 合計の最終結果は、キーが見つからない場合、の影響を受けてはなりません。いずれのキーも存在しない場合、ゼロは和の結果でなければならない。

+1

ジェネレータ式では 'try'を使用できません。 'dct.get(k)'を使わない方がいいでしょう。キーが見つからなければエラーではなく 'None'を返します。キーが見つからない場合(たとえば、「0」と数えられるはずです)、コードの正しい動作は何ですか? – jonrsharpe

+0

キーが見つからない場合は、残りのキーを使用してキーを続行する必要があります。 (私はこの事件を説明するために私の記述を更新する - これに気付いてくれてありがとう) – Yannis

答えて

1

まあ、いくつかのオプションがあり、1が使用するのが好ましいdict.get()

# 1 
sum(dct.get(k, 0) for k in lst) 
# 2 
sum(dct[k] for k in lst if k in dct) 

オプションの1つは、それを反復する前にlstをフィルタリングすることです。

sum(dct[k] for k in filter(lambda i: i in dct, lst)) 

そして、あなたはsumの代替としてフィルタリングされたリストにreduce functionを使用することができます。

reduce(lambda a, k: a + dct[k], filter(lambda i: i in dct, lst)) 

今度はtimeitで最速のアプローチを見つけてみましょう:

from timeit import timeit 
import random 

lst = range(0, 10000) 
dct = {x:x for x in lst if random.choice([True, False])} 

via_sum = lambda:(sum(dct.get(k, 0) for k in lst)) 
print("Via sum and get: %s" % timeit(via_sum, number=10000)) 
# Via sum and get: 16.725695848464966 

via_sum_and_cond = lambda:(sum(dct[k] for k in lst if k in dct)) 
print("Via sum and condition: %s" % timeit(via_sum_and_cond, number=10000)) 
# Via sum and condition: 9.4715681076 

via_reduce = lambda:(reduce(lambda a, k: a + dct[k], filter(lambda i: i in dct, lst))) 
print("Via reduce: %s" % timeit(via_reduce, number=10000)) 
# Via reduce: 19.9522120953 

だから、最速のオプションは、内のif文を経由してアイテムを合計することですジェネレータ表現

sum(dct[k] for k in lst if k in dct) # Via sum and condition: 9.4715681076 

グッドリックk!

+0

素晴らしいと完全な答え。あなたがこれらの4つのオプションを比較する際にいくつかの洞察を提供できるかどうか不思議です。具体的には、第3のオプションと第1の2つを比較する方法です。その中に効率性の向上や「Pythonic」アプローチがありますか? – Yannis

+0

@Yannisありがとう、確かに)時間メトリクスで更新された答えを見てください:)私の推測勝者方法は、ほとんどの 'Pythonic' –

1
sum(dct[k] for k in lst if k in dct) 
+0

本当に役に立つ答え。他の人もこのアプローチについて言及しましたが、私が見ることのできるものから、あなたのものは最速のものではありませんでした。申し訳ありません – Yannis

2

あなたは、単に辞書のキーの値を取得しようとする.get()を使用することができ、そしてこの場合には0になりNone、またはご提供するデフォルトのパラメータを返します見つけるべきではありません。

>>> dct = {1:2, 3:4, 5:6} 
>>> lst = [1,5] 
>>> sum(dct.get(k, 0) for k in lst) 
8  

は、キーの一部(または全部)が存在しない場合には、合計はまだ正常に機能します。

>>> lst = [10, 11] 
>>> sum(dct.get(k, 0) for k in lst) 
0 
5

は、次の2つのオプションがあります。キーは

sum(dct[k] for k in lst if k in dct) 

または使用して存在するかどうかのチェック

dct.get(k, 0)戻っdct[k]k場合dctかでキーをあるget

sum(dct.get(k, 0) for k in lst) 

0もしそうでなければ。見つからない場合は

1

あなたはデフォルト値を提供するために、辞書のget -methodを使用することができます。

sum(dct.get(k, 0) for k in lst) 
関連する問題