2012-08-08 1 views
2

,이 있습니다효율적으로 키 - 값 쌍을 반전 할 한 라이너를 작성 및 OrderedDict을 반대하는 많은 시도 후

from collections import OrderedDict as OD 

    attributes=OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G'))) 
    print(attributes) 

    reversed_attributes=OD(reversed(list(attributes.items()))) 
    print(reversed_attributes) 

    inverted_attributes=OD([reversed(item) for item in attributes.items()]) 
    print(inverted_attributes) 

    ''' Prints 
     OrderedDict([('brand', 'asus'), ('os', 'linux'), ('processor', 'i5'), ('memory', '4G')]) 
     OrderedDict([('memory', '4G'), ('processor', 'i5'), ('os', 'linux'), ('brand', 'asus')]) 
     OrderedDict([('asus', 'brand'), ('linux', 'os'), ('i5', 'processor'), ('4G', 'memory')]) 
    ''' 

이 작동하지만 비효율적이다 ? reverse (list (a.items()))를 사용하면 오버 헤드가 많이 발생하므로 파이썬이 아닌가? inverted_attributes와 동일합니다.

점 등등 루프를 방지하고, 그러나 우리는이 감소 성능을 확장 할 수로?

+0

'반전 (목록 (a.items을())) 당신이 불필요을 반복 다음,'list'를 생성하고 있기 때문에'많은 오버 헤드를 생성 반대로. 'list' 생성자를 제거하면'items'를 역순으로 반복 할 것입니다 (중간 복사는 없습니다). 비슷하게, 새로운'OrderedDict'를 초기화 할 때, 무언가 중간의'list's를 피하기 위해,리스트 이해력이 아닌 생성자 표현식 (주위에'[]')을 사용하고 싶습니다. – ShadowRanger

답변

3

재미 나는 다른 방법을 함께했다.

>>> from collections import OrderedDict as OD 
>>> attributes = OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G'))) 

당신이

>>> reverse = OD(attributes.items()[::-1]) 

또는 더 파이썬 접근 할 수 되돌리고 싶은 경우 :

>>> reverse = OD(reversed(attributes.items())) 

참고는 list 항목을 만들 필요가 없습니다 이미 목록입니다 reversed이 생성자 인 동안 OrderedDict은 단순히 반복하여 새로운 dict을 생성합니다.

모두 유사한 타이밍 발생.

$ python -m timeit "from collections import OrderedDict as OD; attributes = OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G')))" "reverse = OD(attributes.items()[::-1])" 
10000 loops, best of 3: 54.8 usec per loop 
$ python -m timeit "from collections import OrderedDict as OD; attributes = OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G')))" "reverse = OD(reversed(attributes.items()))" 
10000 loops, best of 3: 54.4 usec per loop 
$ python -m timeit "from collections import OrderedDict as OD; attributes = OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G')))" "reversed_attributes=OD(reversed(list(attributes.items())))" 
10000 loops, best of 3: 54.4 usec per loop 

당신이 반전 할 경우 :

>>> invert = OD(zip(*zip(*attributes.items())[::-1])) 

이상 파이썬 :

>>> invert = OD(map(reversed, attributes.items())) 

을 다시 모두 생성 비슷한 타이밍을.

$ python -m timeit "from collections import OrderedDict as OD; attributes = OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G')));" "invert = OD(zip(*zip(*attributes.items())[::-1]))" 
10000 loops, best of 3: 57 usec per loop 
$ python -m timeit "from collections import OrderedDict as OD; attributes = OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G')));" "invert = OD(map(reversed, attributes.items()))" 
10000 loops, best of 3: 56.8 usec per loop 
$ python -m timeit "from collections import OrderedDict as OD; attributes = OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G')));" "inverted_attributes=OD([reversed(item) for item in attributes.items()])" 
10000 loops, best of 3: 55.8 usec per loop 

두 가지 방법을 역 및 반전 함께 사용할 수 있습니다.

이 작동하지만, 비효율적이다? reverse (list (a.items()))를 사용하면 오버 헤드가 많이 발생하므로 파이썬이 아닌가? inverted_attributes와 동일합니다.

뭔가 많은 오버 헤드를 생성하고 매우 파이썬 할 수 있습니다 매우 매우 효율적이 아닌 다른 한편 무엇인가에 파이썬 수, 기간은 약간 학대,하지만 그게 바로 내 의견

발휘에서 할 수 있습니다 위키 백과 :

파이썬 커뮤니티의 일반적인 신조어는 pythonic이며 프로그램 스타일과 관련된 다양한 의미를 가질 수 있습니다. 코드가 파이썬이라고 말하는 것은 파이썬 이디엄을 잘 사용한다는 것입니다. 즉 자연 스럽거나 언어에 유창함을 보여줍니다. 마찬가지로 Python이라는 인터페이스 또는 언어 기능에 대해 Python 관용구와 잘 어울리 며 사용법이 나머지 언어와도 잘 맞는다는 의견을 말합니다. 반면

는 unpythonic 코드의 표시는 C++를 작성하는 시도하는 (또는 리스프, 펄, 또는 Java)에서 코드를 파이썬 즉, 거친 전사가 아닌 다른 언어의 형태의 관용적 번역을 제공합니다.Pythonicity의 개념은 Python의 최소한의 가독성 철학에 밀접하게 연결되어 있으며 "한 가지 이상의 방법이 있습니다"접근법을 피합니다. 읽을 수없는 코드 또는 이해할 수없는 관용구는별로 만족스럽지 않습니다.

하지만 우리는이 감소 성능을 확장 할 수 같이 경우와

?

왜 이런 변형이 일어나는지, 시스템의 필수적인 부분인지 여부를 모르는 채로 근본적으로 최소한의 시간에 선형 시간/공간 오버 헤드가 추가 될 수도 있고 그렇지 않을 수도 있습니다 항목 수가 적다면 문제는 없지만 모든 요청에 ​​대해 웹 서버에서 이러한 상황이 발생한다고 가정하면 큰 dicts에서이 작업을 수행 할 수 있습니다.이 작업은 매우 까다로울 수 있으므로 피하기 위해 다시 디자인해야 할 수 있습니다 이.

+1

samy.vilar, 대단히 감사 드리며 많은 것을 배웠으며 우편 번호,지도 및 시간 정보를 많이 배웠습니다. 저는 처음 프로그래머입니다. 그래서이 시점에서 무엇이 '파이썬'인지에 대해 걱정할 필요가 없습니다. –

+0

@ user1583728 문제 없음, 계속 배우고 Python을 즐기시기 바랍니다 :) –

+0

@SamyVilar : 질문은 Python 3.x 태그가 붙어 있습니다. 타이밍 테스트는 Python 2.x에서 실행되는 것처럼 보이는데, 동작에 큰 차이가 있습니다 (예 :'map' /'zip' /'dict.items' 등)는 생성자와 뷰가 아닌 중간 목록을 생성합니다. – ShadowRanger

0

파이썬 3.x에서 이것을 수행하는 가장 좋은 방법은 불필요한 중간 인 list을 피하는 것입니다. 당신은 모든 솔루션을 가까이서 다뤘지만 항상 목록 이해 또는 list() 생성자를 불필요하게 사용했습니다. 모두에게 가장 파이썬 방법은 역 파이썬 3.x를의 반전은 다음과 같습니다

reversed_and_inverted = OD((v, k) for k, v in reversed(attributes.items())) 

이 더 빨리 (점근) 약간 덜 파이썬이지만, 반면 :

reversed_and_inverted = OD(map(reversed, reversed(attributes.items()))) 

이것은 발전기 식을 사용 중간에 복사본이없는 이전 버전에서 새로운 OrderedDict을 초기화하십시오. 이 vk과 상관 없으므로 CPython은 과 같은 고정 길이 사용을 최적화하여 malloc/free 오버 헤드를 방지합니다.

마찬가지로, 하나 또는 다른 일을 위해 :

# Remove list() wrapper to save copy 
reversed_attributes=OD(reversed(attributes.items())) 

# Remove list comprehension brackets to generate into the OrderedDict directly 
# Explicitly unpack and reverse key and value (repeated calls to reversed 
# built-in invoke expensive LEGB and function call machinery) 
inverted_attributes=OD((v, k) for k, v in attributes.items()) 

# Or faster, but slightly less Pythonic in some people's opinions 
inverted_attributes=OD(map(reversed, attributes.items())) 

(가) 내장하는 방식 사이의 비율 차이 실제로 문제가 다소 빠른만큼 OrderedDict 실행 3.5의 같은 일부 타이밍을. 나는 단순화하기 위해 ipython%timeit 마법을 사용하고 있습니다 :

# Make a dict large enough that the differences might actually matter 

>>> od1 = OrderedDict(enumerate(string.ascii_uppercase)) 
>>> %timeit -r5 OrderedDict(reversed(od1.items())) 
100000 loops, best of 5: 7.29 μs per loop 

# Unnecessary list-ification of items view adds ~15% to run time 
>>> %timeit -r5 OrderedDict(reversed(list(od1.items()))) 
100000 loops, best of 5: 8.35 μs per loop 

>>> %timeit -r5 OrderedDict((v, k) for k, v in od1.items()) 
100000 loops, best of 5: 10 μs per loop 

# Surprisingly, runs a little faster as a list comprehension; likely a 
# coincidence of construction of OrderedDict from an input of known length 
# being optimized to presize the output dict (while lists are optimized for 
# reading from unknown length input iterable) 
>>> %timeit -r5 OrderedDict([(v, k) for k, v in od1.items()]) 
100000 loops, best of 5: 9.34 μs per loop 

# map produces a generator that knows how long it is if the input also knows 
# how long it is, so we can beat either one in this case by avoiding repeated 
# lookups of reversed and execution of Python level byte code via: 
>>> %timeit -r5 OrderedDict(map(reversed, od1.items())) 
100000 loops, best of 5: 8.86 μs per loop 
+0

Note : 예제 입력 값이 작기 때문에, 타이밍은 여러분에게별로 알려주지 않을 것입니다. 특히 Python 3.5 이전 버전에서는'OrderedDict'가 내장되어 있지 않습니다 (이것은 파이썬은 클래스를 정의했다.) 그리고 그것을 반복하고 그것을 구성하는 오버 헤드는 다른 대부분의 비용을 줄이려고한다. – ShadowRanger