在多次尝试创建将反转键值对的单行并反转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()))这会产生很多开销,所以不是pythonic吗?对于inverted_attributes也一样。
重点是避免循环等等,但这会在我们扩大规模时降低性能吗?
答案 0 :(得分:4)
有趣的是我也提出了其他方法。
>>> from collections import OrderedDict as OD
>>> attributes = OD((('brand','asus'), ('os','linux'), ('processor','i5'), ('memory','4G')))
如果你想扭转你可以做到这一点
>>> reverse = OD(attributes.items()[::-1])
或更加pythonic的方法:
>>> 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]))
或更多pythonic:
>>> 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
你可以将这两种方法结合使用来反转和反转。
有些东西可以产生大量的开销,而另一方面是pythonic的东西可以非常高效而且不是非常pythonic,这个术语有点滥用,但这只是我的意见这有效,但效率低吗?通过使用reverse(list(a.items()))这会产生很多开销,所以不是pythonic吗?对于inverted_attributes也一样。
来自维基百科:
Python社区中常见的新词是pythonic,它可以具有与程序风格相关的广泛含义。要说代码是pythonic就是说它很好地使用了Python习语,它很自然或者说流利的语言。同样地,对于一个接口或语言特征来说它是pythonic就是说它适用于Python习语,它的使用与其他语言很好地融合。
相比之下,unpythonic代码的标志是它试图用Python编写C ++(或Lisp,Perl或Java)代码 - 即提供粗略的转录而不是来自另一种语言的形式的惯用翻译。 pythonicity的概念与Python的极简主义可读性哲学紧密相关,并避免了“有多种方法可行”的方法。难以理解的代码或难以理解的习语是单声道的。
至于:
但随着我们的扩大,这会降低性能吗?
这很难说,不知道你为什么要进行这样的转换,或者它们是否是你系统中不可或缺的一部分,从根本上来说,它们正在增加线性时间/空间开销,这可能会或可能不会很好,如果条目的数量仍然很小,那么没有问题,但是如果在每次请求时,假设在Web服务器上发生这种情况,那么你就是在大量的情况下这样做,这可能非常苛刻,并且可能需要重新设计以避免这种情况。 / p>
答案 1 :(得分:0)
在Python 3.x中,最好的方法是避免不必要的中间list
。您接近了所有解决方案,但是您总是不必要地使用列表解析或list()
构造函数。在Python 3.x中反转和反转的最Pythonic方法是:
reversed_and_inverted = OD((v, k) for k, v in reversed(attributes.items()))
虽然这稍微低于Pythonic,但更快(渐近):
reversed_and_inverted = OD(map(reversed, reversed(attributes.items())))
这使用生成器表达式从旧的OrderedDict
初始化,没有中间副本(创建tuple
v
和k
的反向tuple
没关系; 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
的{{1}}魔术来简化:
# 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