2011-10-28 4 views
12

사전에 데이터가 있습니다 .. NOW 나는 사용자로부터 입력을 받아 들여 아무 것도 될 수 없습니다 .. 그리고 나는 수행원. 키가 있으면 차갑게 .. 사전에서 값을 가져옵니다. 그렇지 않으면 가장 가까운 숫자를 가져옵니다.파이썬 : 주어진 입력 키의 사전에서 가장 가까운 키를 찾습니다

197,202,208... 

그럼 아마 202 뷰 알고리즘의 관점에서하기 (200)에 가장 가까운 키 .. 이다 .... : 입력 용 키 example..if 을하고 키 같다. 그것의 똑 바른 앞으로. 그러나 이것을하는 pythonic 방법 있는가? 감사합니다

+4

"dict"이어야하거나 "사전 형"객체로 충분합니까? 대신 이진 트리 또는 정렬 된 목록을 사용하면 이진 검색을 사용하여 O (log n) 시간에 가장 가까운 키를 찾을 수 있습니다. –

+1

"알고리즘의 관점에서 볼 때 그 직설적 인"... 나는 O (log n) 해법이 덜 수월하기 때문에 당신이 O (n) 해법으로 괜찮다고 가정한다. –

답변

17

여기에 한 줄에 함수입니다 :

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을하기 : 키가 DICT 사용에있을 때 분을 평가하지에 당신은 다음을 사용할 수 있습니다 :

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

유감스럽게도 키가 데이터에 있어도 모든 조회에 대해 'min (data.keys() ...)'을 평가합니다. 어쩌면 get 논리를 3 진법으로 나눌 수 있습니다. 'data num'데이터가 num 인 경우 다른 데이터 [min (data.keys(), key = lambda k : abs (k-num))] – PaulMcG

+0

감사합니다. 귀하의 조언에 대한 응답을 편집했습니다. – Will

+1

기꺼이 도와 드리 겠으나'd.has_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) 

주 : fthis question입니다.

1

만약 당신이 가지고있는 모든 것이 파이썬 사전이라면, 사전에있는 모든 항목을 확인하는 것보다 더 잘 할 수는 없습니다 (Will의 답과 같습니다). 그러나 가장 가까운 키를 찾으려면 (O(N) 대신 O(log N)), 일종의 균형 잡힌 트리가 필요합니다.

불행히도 파이썬이 표준 라이브러리에서 이와 같은 데이터 구조를 갖고 있다고 생각하지 않습니다. Python 방식은 대신에 dict를 사용하는 것입니다. 따라서 큰지도에서 이러한 많은 쿼리를 수행 할 생각이라면 최상의 선택은 확장 라이브러리를 찾거나 자신의 롤을 찾는 것일 수도 있습니다 ...

+1

당신이 묘사하는 것에 대해'bisect'를 확인하십시오. 키에 대한 bisect와 키 - 값 매핑에 대한 dict를 사용하여 클래스를 만듭니다. bisect를 사용하여 키 목록에서 새 키의 적절한 삽입 지점을 찾은 다음 인접 값을 확인하여 어느 것이 더 가까운 지 확인하십시오. – PaulMcG

21

이 문제는 dict 키가 더 많이 만들어집니다. 특별한 순서는 없습니다. dict을 어떻게 만드는지 (예제와 같이) 재생할 수 있고 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

파이썬 3.6에서 해결책을 시도 할 때'TypeError : 'odict_keys'객체가 색인 생성을 지원하지 않습니다. –

+1

이것은 bisect.bisect_left (list (a.keys()), 45.3)를 사용하여 수정할 수 있습니다. ' –

12

오히려 OrderedDict을 사용하여 이등분보다는 sortedcontainersSortedDict 모듈의 유형을 고려한다. 그것은 pure-Python이고 fast-as-C implementation의 sorted list, dict 및 set 유형으로 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

어떻게' SortedDict()'는 부정적인 키 값을 처리합니까? – cosmictypist

+0

'SortedDict()'를 사용했지만 음수 값의 키를 잘못 정렬합니다. – cosmictypist

+0

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

관련 문제