当前位置: 首页 > 面试题库 >

在Python中复制数组/列表的有效方法

毕泽宇
2023-03-14
问题内容

注意:我是一名Ruby开发人员,试图在Python中找到自己的方式。

当我想弄清楚为什么某些脚本使用mylist[:]而不是list(mylist)复制列表时,我对各种复制方法进行了快速基准测试range(10)(请参见下面的代码)。

编辑: 我更新了测试以使用Python timeit,如下所示。这使得不可能直接将其与Ruby进行比较,因为 timeit
不能解决Ruby的循环Benchmark问题,因此Ruby代码仅供 参考

Python 2.7.2

Array duplicating. Tests run 50000000 times
list(a)     18.7599430084
copy(a)     59.1787488461
a[:]         9.58828091621
a[0:len(a)] 14.9832749367

作为参考,我也用Ruby编写了相同的脚本:

红宝石1.9.2p0

Array duplicating. Tests 50000000 times
                      user     system      total        real
Array.new(a)     14.590000   0.030000  14.620000 ( 14.693033)
Array[*a]        18.840000   0.060000  18.900000 ( 19.156352)
a.take(a.size)    8.780000   0.020000   8.800000 (  8.805700)
a.clone          16.310000   0.040000  16.350000 ( 16.384711)
a[0,a.size]       8.950000   0.020000   8.970000 (  8.990514)

问题1: 什么是mylist[:]不同的方式来做,这是 25%,
甚至比快mylist[0:len(mylist)]。它直接复制到内存中还是什么?

问题2: 编辑: 更新的基准测试不再显示Python和Ruby的巨大差异。 是:
我是否以某种明显低效的方式实施测试,以便Ruby代码比Python快得多?

现在的代码清单:

蟒蛇:

import timeit

COUNT = 50000000

print "Array duplicating. Tests run", COUNT, "times"

setup = 'a = range(10); import copy'

print "list(a)\t\t", timeit.timeit(stmt='list(a)', setup=setup, number=COUNT)
print "copy(a)\t\t", timeit.timeit(stmt='copy.copy(a)', setup=setup, number=COUNT)
print "a[:]\t\t", timeit.timeit(stmt='a[:]', setup=setup, number=COUNT)
print "a[0:len(a)]\t", timeit.timeit(stmt='a[0:len(a)]', setup=setup, number=COUNT)

红宝石:

require 'benchmark'

a = (0...10).to_a

COUNT = 50_000_000

puts "Array duplicating. Tests #{COUNT} times"

Benchmark.bm(16) do |x|
  x.report("Array.new(a)")   {COUNT.times{ Array.new(a) }}
  x.report("Array[*a]")   {COUNT.times{ Array[*a] }}
  x.report("a.take(a.size)")   {COUNT.times{ a.take(a.size) }}
  x.report("a.clone")    {COUNT.times{ a.clone }}
  x.report("a[0,a.size]"){COUNT.times{ a[0,a.size] }}
end

问题答案:

使用timeitpython中的模块测试计时。

from copy import *

a=range(1000)

def cop():
    b=copy(a)

def func1():
    b=list(a)

def slice():
    b=a[:]

def slice_len():
    b=a[0:len(a)]



if __name__=="__main__":
    import timeit
    print "copy(a)",timeit.timeit("cop()", setup="from __main__ import cop")
    print "list(a)",timeit.timeit("func1()", setup="from __main__ import func1")
    print "a[:]",timeit.timeit("slice()", setup="from __main__ import slice")
    print "a[0:len(a)]",timeit.timeit("slice_len()", setup="from __main__ import slice_len")

结果:

copy(a) 3.98940896988
list(a) 2.54542589188
a[:] 1.96630120277                   #winner
a[0:len(a)] 10.5431251526

当然,其中涉及的额外步骤a[0:len(a)]是速度缓慢的原因。

这是两者的字节码比较:

In [19]: dis.dis(func1)
  2           0 LOAD_GLOBAL              0 (range)
              3 LOAD_CONST               1 (100000)
              6 CALL_FUNCTION            1
              9 STORE_FAST               0 (a)

  3          12 LOAD_FAST                0 (a)
             15 SLICE+0             
             16 STORE_FAST               1 (b)
             19 LOAD_CONST               0 (None)
             22 RETURN_VALUE

In [20]: dis.dis(func2)
  2           0 LOAD_GLOBAL              0 (range)
              3 LOAD_CONST               1 (100000)
              6 CALL_FUNCTION            1
              9 STORE_FAST               0 (a)

  3          12 LOAD_FAST                0 (a)    #same up to here
             15 LOAD_CONST               2 (0)    #loads 0
             18 LOAD_GLOBAL              1 (len) # loads the builtin len(),
                                                 # so it might take some lookup time
             21 LOAD_FAST                0 (a)
             24 CALL_FUNCTION            1         
             27 SLICE+3             
             28 STORE_FAST               1 (b)
             31 LOAD_CONST               0 (None)
             34 RETURN_VALUE


 类似资料:
  • 问题内容: 在python中旋转列表的最有效方法是什么?现在我有这样的事情: 有没有更好的办法? 问题答案: 已针对两端的推拉进行了优化。他们甚至有专门的方法。

  • 我不是本地JAVA程序员。我正在为web服务API创建一个客户端。API基本上需要一个数组参数。 我正在解析一个XML文件,创建记录,然后使用此API进行批量插入。 问题是这个API一次只能插入200条记录,这意味着我的数组在调用时只能有200条或更少的记录。 由于我不知道预先有多少条记录,所以我将我的记录存储在ArrayList中,然后使用将其转换为Array。ToArray() 现在,由于AP

  • 问题内容: 我想复制一个2D列表,以便如果我修改一个列表,则不修改另一个列表。 对于一维列表,我只是这样做: 现在,如果我修改了b,a就不会修改。 但这不适用于二维列表: 如果我修改了b,a也会被修改。 我该如何解决? 问题答案: 对于不管尺寸多少都可以工作的更通用的解决方案,请使用:

  • 问题内容: 我已经开发了像这样的数组列表 现在我的问题是:如果我想从列表中删除“ 8”,哪种方法更好? 第一种方式: 第二种方式: 现在,请从性能的角度建议其中哪一个效率更高,速度更快,并且还有其他任何类似于内置函数的方法,通过使用它,我们可以删除重复项而无需进行过多迭代。 问题答案: 在性能方面,它们应该相似。你测试了吗 如果要使用内置方法,则可以达到类似的性能(通过测试确认): 最后,如果您想

  • 我需要从一个列表中追加一些重复的值到一个子列表中,让我用一个例子来解释: 我有一个名为的变量,它包含大写字母字符串和符号。 我的最终目标是拥有这个数组: 在示例中,我需要将所有的符号分组到原始中的子列表中,我想过在数组中迭代,找到当前附近的所有符号,然后创建第二个数组,但我想也许还有更多的pythonic我可以做的,有什么想法吗?

  • 问题内容: 我正在寻找一种类似于R函数的高效方法来计算Python中列表的秩向量。在一个简单的列表与所述元件之间没有联系,元件 我 的列表的秩矢量的应该是 X 当且仅当是 X 个在排序的列表元素。到目前为止,这很简单,以下代码片段可以解决问题: 但是,如果原始列表具有联系(即,多个具有相同值的元素),事情就会变得复杂。在这种情况下,所有具有相同值的元素都应具有相同的等级,这是使用上述朴素方法获得的

  • 问题内容: 我在与OS无关的文件管理器中工作,并且正在寻找为Linux复制文件的最有效方法。Windows有一个内置函数CopyFileEx(),但是据我所知,Linux没有这种标准函数。所以我想我将必须实现自己的。明显的方法是fopen / fread / fwrite,但是是否有更好(更快)的方法呢?我还必须有能力每隔一段时间停止一次,以便可以更新文件进度菜单的“到目前为止”。 问题答案: 不

  • 问题内容: 我希望编写一个提供JSON对象列表的Web服务。返回以下内容的JSON是否有效: 还是将其放在单个对象中以返回的“正确”方法: 问题答案: 两种形式均有效。但是,对于API,我建议使用第二种形式。原因是它为您提供扩展API的途径。 例如,如果您有一个返回用户对象数组的API ,后来又决定要包含一些有关返回用户的汇总统计信息,那么没有不破坏现有客户端(或包括每个用户对象中有很多冗余数据)