2012-08-08 69 views
2

许多尝试创建单行将反转键值对,和反向的OrderedDict后,我有这样的:反转和反python3.x 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')]) 
    ''' 

这工作,但它是效率低下?通过使用反转(列表(a.items()))这是否产生了很多开销,所以不是pythonic? reverse_attributes也一样。

问题的关键在于避免出现循环等问题,但是这会降低性能吗?

+0

'逆转(名单(a.items()))'产生很大的开销,因为你无需创建一个'list',然后它迭代相反。删除'list'构造函数会直接反转'items'(不需要中间复制)。同样,当初始化新OrderedDict时,你想使用一个生成器表达式(w/o'[]'),而不是列表理解,以避免创建无意义的中间列表。 – ShadowRanger 2015-10-19 13:48:56

回答

3

有趣我也想出了其他方法。

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

,如果你想扭转你可以做到这一点

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

或更Python的方法:

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

注意到你不需要创建list项目已经是一个列表,而reversed是一个生成器OrderedDict将简单迭代到它生成新的字典。

两者都产生类似的时间。

$ 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])) 

或更Python:

>>> 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 

您可以结合使用这两种方法来反转和反转。

这有效,但效率不高?通过使用反转(列表(a.items()))这是否产生了很多开销,所以不是pythonic? reverse_attributes也一样。

东西能产生大量的开销,是对另一方面的东西可以非常非常有效的,而不是很Python的Python的,这个词已经被有点虐待,但是那只是我的意见

使出wikipedia:

Python社区中的一个常见新词是pythonic,它可以与程序风格有广泛的含义。要说代码是pythonic,就是说它很好地使用了Python成语,它是自然的或者表现出流畅的语言。同样,说一个接口或语言特性,它是pythonic是说,它适用于Python成语,它的使用与其他语言良好的衔接。

相反,unpythonic代码的一个标志是它试图用Python编写C++(或Lisp,Perl或Java)代码 - 也就是说,它提供了一个粗略的转录,而不是来自另一种语言的表单的惯用翻译。pythonicity的概念与Python的极简主义可读性哲学紧密相连,并且避免了“有多种方法可行”的方法。无法读取的代码或难以理解的习惯用法是不合理的。

为:

但这种减少表现为我们扩大规模?

这很难说,不知道为什么要做出这样的变换,或者判断你的系统的一个组成部分,从根本上裸minimun他们增加线性时间/空间开销可能会或可能不会如果条目数量仍然很少,那么没有问题,但如果在每次请求时,假设这发生在网络服务器上,那么您的这些操作是在大量的字符上进行的,这可能会非常严酷,并且可能需要重新设计以避免这个。

+1

samy.vilar,非常感谢你的回应 - 学到了很多东西,并且对zip,map和timeit有很多了解。我是一个开始的程序员,所以在这个时候也许不应该担心什么是和不是'pythonic'。 – 2012-08-08 08:11:27

+0

@ user1583728没问题,我希望你不断学习和享受python :) – 2012-08-08 08:17:45

+0

@SamyVilar:这个问题被标记为Python 3.x;你的计时测试看起来是在Python 2.x上运行的,这会在行为上产生巨大的差异(例如'map' /'zip' /'dict.items'等产生中间列表,而不是生成器和视图。时间将在此基础上被怀疑 – ShadowRanger 2015-10-19 13:50:43

0

在Python 3.x中,最好的方法是避免不必要的中间list s。你在所有解决方案中都很接近,但你总是不必要地使用列表理解或构造函数。到两个最Python的方式扭转和倒置在Python 3.x的将是:

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

而此略少是Python化,但即使是更快(渐近):

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

这使用生成器表达式从旧版本初始化新的OrderedDict,没有中间副本(创建vk的反转tuple并不重要; CPython优化了固定长度tuple的使用,以避免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())) 

一些时序为3.5,其中内置OrderedDict运行足够快,方法之间的差异百分比实际上事情有点。我使用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

注意:因为示例输入很小,所以定时并不会告诉你很多,特别是在Python 3.5之前,OrderedDict不是内置的(它被实现为Python定义的类)以及迭代它并构建它的开销将会消耗大部分其他成本。 – ShadowRanger 2015-10-19 14:00:27