我知道Python不是为速度而构建的,但我想提高以下代码的性能:
listA = [1,2]
listB = [1,2,3,4,5,6,7,8,9,10]
# pre-allocate for speed. Appending empty list is slower?
newList = ['NaN']*len(listB)
# Do I need a loop? Can I use something faster?
for n in xrange(len(listB)):
if listB[n] % 2 == 1:
newList[n] = listA[0]
else:
newList[n] = listA[1]
我的问题是listB
可能变得非常大。
我已经预先为newList
分配了内存并使用了xrange
。我相信这些可以为大型列表提供显着的速度提升。
但是我甚至需要一个for循环,因为每个循环都不依赖于之前的结果。 python是否有数组类型?
我可以解析listB
并在Matlab中并行运行类似于parfor
的操作吗?
其他信息: 对于我的问题,随着listA变得越来越大,listB的指数也越来越大。
对于listB中的每个项目,都需要在listA中进行查找。然后执行计算(不必以模为单位),并将结果附加到newList。然后我对newList进行统计分析(比较简单来说就是平均值)。 newList的长度始终与listB相同。
答案 0 :(得分:3)
最短,也许是最快的方式是使用列表理解:
newList = [listA[1 - x%2] for x in listB]
答案 1 :(得分:3)
xrange
的目的不是为了获得速度;其目的是减少内存使用量。 range(N)
和xrange(N)
之间的区别在于后者不会扩展为大小为N的列表,而是扩展为小型生成器对象。
一些提示:
如果您的列表很大,请查看numpy。 Numpy拥有高效的数组处理算法,并在内部使用本机代码。
模数很慢(if listB[n] % 2 == 1:
)。在这种情况下,最好使用按位运算符(if ListB[n]&1
)。
对于范围内 n 的每个值,if
语句可以显示:newList[n] = listA[1-ListB[n]&1]
。反转listA
的顺序以获取1-
的git并保存另一个整数操作。
答案 2 :(得分:1)
使用列表理解似乎缩短了一些时间:
function bones_infinite_loop_init(){
add_theme_support( 'infinite-scroll', array(
'type' => 'scroll',
'container' => 'masonry',
'render' => 'bones_infinite_scroll_render',
'footer' => false
) );
}
add_action( 'init', 'bones_infinite_loop_init' );
function bones_infinite_scroll_render() {
$args = array( 'post_type'=> 'wigwam','post_parent' => 0,'posts_per_page' => 25);
query_posts( $args );
if (have_posts()) :
while (have_posts()) : the_post();
get_template_part( 'content', get_post_format() );
endwhile;
endif;
}
与:相比:
listB = [i for i in xrange(1,1000000)]
start = clock()
listA = [1,2]
for n in xrange(len(listB)):
if listB[n] % 2 == 1:
newList[n] = listA[0]
else:
newList[n] = listB[1]
print "Time taken = %.5f" % (clock() - start)
>>> 0.21216
答案 3 :(得分:1)
首先,使用按位和运算符n % 2
替换模运算符n & 1
。接下来,不要通过索引访问listB
,而是直接使用in
遍历其项目。您可以完全删除listA。这些小改进应该可以加快速度。
newList = ((n & 1) + 1 for n in listB)
这段代码的真正优点在于它是一个生成器理解,而不是列表理解。虽然这并没有使它更快,但确实使它的内存效率更高。话虽如此,它也有一些缺点;你无法访问整个列表,一旦你访问了一个值它就消失了。如果您只打算迭代newList
或对newList的每个项目执行一些计算,那么这将没问题。如果没有,那么使newList
成为列表理解:
newList = [(n & 1) + 1 for n in listB]
祝你好运!
答案 4 :(得分:0)
只需循环遍历listB并在开始时设置两个变量,而不是重复索引:
newList = []
i, j = listA[0], listA[1]
for n in listB:
if n % 2:
newList.append(i)
else:
newList.append(j)
或使用列表comp:
[i if n % 2 else j for n in listB]
时序:
In [4]: %%timeit
newList = ['NaN']*len(listB)
for n in xrange(len(listB)):
if listB[n] % 2 == 1:
newList[n] = listA[0]
else:
newList[n] = listA[1]
...:
100000 loops, best of 3: 2.33 µs per loop
In [5]: %%timeit
...: i,j = listA[0], listA[1]
...: [i if n % 2 else j for n in listB]
...:
1000000 loops, best of 3: 1.12 µs per loop
In [16]: %%timeit
....: newList = []
....: i,j = listA[0], listA[1]
....: for n in listB:
....: if n % 2 == 1:
....: newList.append(i)
....: else:
....: newList.append(j)
....:
1000000 loops, best of 3: 1.88 µs per loop
In [18]: timeit [listA[1 - x%2] for x in listB]
1000000 loops, best of 3: 1.38 µs per loop
使用if n& 1稍微快一些:
In [11]: %%timeit
i,j = listA[0], listA[1]
[i if n & 1 else j for n in listB]
....:
1000000 loops, best of 3: 1.04 µs per loop
因此,无论是在列表comp还是循环中,索引总是会增加更多开销。当你只想要这两个值时,无意义地不断索引listA。
如果你想用cython进行更多的速度编译,只需键入几个变量就可以缩短运行时间:
In [31]: %%cython
....: def faster(l1,l2):
....: cdef int i,j,n
....: i, j = l1[0], l2[1]
....: return [i if n & 1 else j for n in l2]
....:
In [32]:
In [32]: timeit faster(listA,listB)
1000000 loops, best of 3: 455 ns per loop
如果您正在进行大量的数值计算,您可能需要进一步了解cython和/或numpy。