【问题标题】:Alternatives/Faster ways to list.extend in python?在python中list.extend的替代方法/更快的方法?
【发布时间】:2019-04-05 14:30:42
【问题描述】:

我有相当多的数据集要扩展。

我想知道有什么替代/更快的方法。

iadd 和extend 我都试过了,它们都需要很长时间才能创建输出。

from timeit import  timeit

raw_data = [];
raw_data2 = [];
added_data = range(100000)

# .__iadd__
def test1():
    for i in range(10):
        raw_data.__iadd__(added_data*i);

#extend

def test2():
    for i in range(10):
        raw_data2.extend(added_data*i);


print(timeit(test1,number=2));
print(timeit(test2,number=2));

我觉得列表理解或数组映射可以回答我的问题...

【问题讨论】:

  • 请使用timeit stdlib 模块或其他一些分析工具,time.time 在单个范围内执行不合适
  • @AzatIbrakov,好的。谢谢,我看看这个功能。
  • @AzatIbrakov,建议将 time.time 替换为 timeit,谢谢!
  • @PatrickArtner,谢谢,标签已被移除。

标签: python python-2.7


【解决方案1】:

如果您需要将数据作为列表,则没有什么好处 - list.extend__iadd__ 在性能上非常接近 - 取决于您使用的数量,其中一个是最快的:

import timeit 
from itertools import repeat , chain 
raw_data = [] 
added_data = range(100000) # verify data : uncomment: range(5)

def iadd():
    raw_data = [] 
    for i in range(10):
        raw_data.__iadd__(added_data)
    # print(raw_data)

def extend():
    raw_data = [] 
    for i in range(10):
        raw_data.extend(added_data)
    # print(raw_data)

def tricked():
    raw_data = list(chain.from_iterable(repeat(added_data,10)))
    # print(raw_data)

for w,c in (("__iadd__",iadd),("  extend",extend),(" tricked",tricked)):
    print(w,end = " : ")
    print("{:08.8f}".format(timeit.timeit(c, number = 200)))

输出:

# number = 20
__iadd__ : 0.69766775
  extend : 0.69303196    # "fastest"
 tricked : 0.74638002


# number = 200
__iadd__ : 6.94286992    # "fastest"
  extend : 6.96098415
 tricked : 7.46355973

如果您不需要这些东西,您最好使用chain.from_iterable(repeat(added_data,10)) 的生成器,而无需创建列表本身以减少使用的内存量。

相关:

【讨论】:

    【解决方案2】:

    我不确定是否有更好的方法来做到这一点,但是使用numpyctypes,您可以为整个数组预分配足够的内存,然后使用ctypes.memmove 将数据复制到 raw_data - 这是现在是ctypes.c_longs 的ctypes 数组。

    from timeit import timeit
    import ctypes
    import numpy
    
    def test_iadd():
        raw_data = []
        added_data = range(1000000)
    
        for i in range(10):
            raw_data.__iadd__(added_data)
    
    
    def test_extend():
        raw_data = []
        added_data = range(1000000)
    
        for i in range(10):
            raw_data.extend(added_data)
        return
    
    
    def test_memmove():
        added_data = numpy.arange(1000000)  # numpy equivalent of range
    
        raw_data = (ctypes.c_long * (len(added_data) * 10))()  # make a ctypes array to contain elements
    
        # the address to copy to
        raw_data_addr = ctypes.addressof(raw_data)
        # the length of added_data in bytes
        added_data_len = len(added_data) * ctypes.sizeof(ctypes.c_long)
        for i in range(10):
            # copy data for one section
            ctypes.memmove(raw_data_addr, added_data.ctypes.data, added_data_len)
            # update address to copy to
            raw_data_addr += added_data_len
    
    
    tests = [test_iadd, test_extend, test_memmove]
    
    for test in tests:
        print '{} {}'.format(test.__name__, timeit(test, number=5))
    

    这段代码在我的电脑上产生了以下结果:

    test_iadd 0.648954868317
    test_extend 0.640357971191
    test_memmove 0.201567173004
    

    这似乎表明使用ctypes.memmove 明显更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-09
      • 2021-12-05
      • 1970-01-01
      • 1970-01-01
      • 2016-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多