2011-10-28 19 views
12

私は辞書の形式でデータを持っています。 NOW私はユーザーからの入力を受け取り、それは何でもよい.. そして私は以下。 キーが存在する場合は、クール..ディクショナリから値を取得します。 もしそうでなければ、最も近いものを数値的に取り出す。ビューのアルゴリズムの観点から、今後Python:指定された入力キーから辞書に最も近いキーを見つけよう

197,202,208... 

おそらく202が200に最も近いキーです.... .. :入力キーexample..ifについては は200 あるなどのキーがあります。その真っ直ぐ前方..しかし、これを行うためのpythonic方法はありますか? ありがとう

+4

それは 'dict'する必要がない、または「辞書のような」オブジェクトで十分でしょうか?バイナリツリーまたはソートリストを使用する場合は、バイナリ検索を使用してO(log n)時間に最も近いキーを見つけることができます。 O(ログn)のソリューションはあまり簡単であるとして、「ビューのアルゴリズムの観点から。そのまっすぐ進む」 –

+1

...私は、これはあなたがO(n)のソリューションで大丈夫意味を前提としています。 –

答えて

17

ここでは1行にあなたの関数です:

data.get(num, data[min(data.keys(), key=lambda k: abs(k-num))]) 

編集:キーは辞書の使用時に分を評価しないように:

data[num] if num in data else data[min(data.keys(), key=lambda k: abs(k-num))] 

またはdata内のすべての値がTrueと評価された場合は、

data.get(num) or data[min(data.keys(), key=lambda k: abs(k-num))] 
+2

残念ながら、これはキーがデータ内にあっても、すべてのルックアップに対して 'min(data.keys()...)'を評価します。たぶん三に入るのロジックを破る: 'データ[NUM]であれば、データの他のデータでNUM [分(data.keys()、キー=ラムダK:ABS(K-NUM))]' – PaulMcG

+0

おかげで、ポール。あなたの助言に応答を編集しました。 – Will

+1

助けてくれて嬉しいですが、 'd_as_key(k)'が 'if k in d'のために推奨されなくなった場合。 – PaulMcG

0

これは、あなたが望むことをしなければなりません(キーから抜くことはできませんが、それを理解することができます:)。

f = lambda a,l:min(l,key=lambda x:abs(x-a)) 
numbers = (100, 200, 300, 400) 
num = int(raw_input()) 
print 'closest match:', f(num, numbers) 

注:fは、this questionです。

1

あなたが持っているものがすべてPython辞書であれば、ウィルの答えのように、辞書のすべての項目をチェックするよりもうまくやることはできません。ただし、最も近いキーをそれよりも効率的に見つけたい場合(O(N)ではなくO(log N))、ある種のバランスのとれたツリーが必要です。

残念ながら、私はPythonが標準ライブラリでそのようなデータ構造を持っているとは思っていません。Pythonの方法は代わりにdictを使うことです。あなたが大規模な地図上で多くのそのようなクエリを行うことを期待している場合は、あなたの最良の選択は、拡張ライブラリを見つけるか、またはあなた自身のロールを見つけることかもしれません...

+1

あなたが描いているものについては、「bisect」をチェックしてください。キーの二等分線とキーと値のマッピングのためのdictを持つクラスを作成します。二等分線を使用して、キーのリストに新しいキーの適切な挿入ポイントを見つけ、隣接する値を調べてどちらが近いかを確認します。 'を行う方法のpython 3.6 – PaulMcG

21

この問題は、特別な順序ではありません。あなたがディクテーションをどのようにして順番に(あなたの例のように)することができ、python> = 2.7を使用すれば、OrderedDictbisectを使ってこの雷を速くすることができます。

import collections 
a = collections.OrderedDict() 
for i in range(100): 
    a[i] = i 

import bisect 
ind = bisect.bisect_left(a.keys(), 45.3) 

は、その後あなただけの要素 indind-1は、このように多くの、より少ない計算を行う、近いであるかを確認する必要があります。スティーブン・Gによって以下に指摘したように


は、のpython3に.keys()はリストだけでなく、一つに変更しなければなりません。

bisect.bisect_left(list(a.keys()), 45.3) 
+1

私は' TypeError例外を取得しますSortedDict() 'は負のキー値を処理しますか? –

+1

にあなたのソリューションをしようと、これは(45.3、リスト(a.keys()))' bisect.bisect_leftを用いて補正することができたときに 'odict_keys' オブジェクトがindexing'をサポートしていません ' –

12

むしろOrderedDictを使用して二分するよりも、sortedcontainersモジュールでSortedDictタイプを検討します。純粋なPythonで、並べ替えられたリスト、辞書、セット型のfast-as-C implementationで、100%のテストカバレッジとストレスの時間があります。あなたが目的のキーのために二等分することができますSortedDictで

。例:

from sortedcontainers import SortedDict 
sd = SortedDict((key, value) for key, value in data) 

# Bisect for the index of the desired key. 
index = sd.bisect(200) 

# With that index, lookup the key. 
key = sd.iloc[index] 

# You can also look ahead or behind to find the nearest key. 
behind = sd.iloc[index - 1] 
ahead = sd.iloc[index + 1] 

PyPIを使用するのはPythonです!

+0

: – cosmictypist

+0

私は 'SortedDict()'を使っていましたが、負の値のキーを間違って並べ替えます。 – cosmictypist

+0

はchristylynn002 @ https://github.com/grantjenks/sorted_containers/issues – GrantJ

関連する問題