簡體   English   中英

連接字符串的速度比附加到列表的速度更快

[英]Concatenating strings faster than appending to lists

我試圖隔離列表中的特定項目(例如[0, 1, 1]將返回[0, 1] )。 我設法解決了這個問題,但是我發現了一些奇怪的事情。

當我嘗試追加列表時,它的運行速度要比連接字符串然后拆分時慢7倍。

這是我的代碼:

import time
start = time.time()

first = [x for x in range(99999) if x % 2 == 0]
second = [x for x in range(99999) if x % 4 == 0]

values = first + second

distinct_string = ""

for i in values:
    if not str(i) in distinct_string:
        distinct_string += str(i) + " "

print(distinct_string.split())

print(" --- %s sec --- " % (start - time.time()))

結果大約在5秒鍾內結束...現在列出:

import time
start = time.time()

first = [x for x in range(99999) if x % 2 == 0]
second = [x for x in range(99999) if x % 4 == 0]

values = first + second

distinct_list = []

for i in values:
    if not i in distinct_list:
        distinct_list.append(i)

print(distinct_list)

print(" --- %s sec --- " % (start - time.time()))

運行約40秒。

即使我將許多值轉換為字符串,是什么使字符串更快?

請注意,通常最好使用timeit來比較函數,該函數可以多次運行同一事物以獲得平均性能,並排除重復的代碼以專注於重要的性能。 這是我的測試腳本:

first = [x for x in range(999) if x % 2 == 0]
second = [x for x in range(999) if x % 4 == 0]

values = first + second

def str_method(values):
    distinct_string = ""
    for i in values:
        if not str(i) in distinct_string:
            distinct_string += str(i) + " "
    return [int(s) for s in distinct_string.split()]

def list_method(values):
    distinct_list = []
    for i in values:
        if not i in distinct_list:
            distinct_list.append(i)
    return distinct_list

def set_method(values):
    seen = set()
    return [val for val in values if val not in seen and seen.add(val) is None]

if __name__ == '__main__':
    assert str_method(values) == list_method(values) == set_method(values)
    import timeit
    funcs = [func.__name__ for func in (str_method, list_method, set_method)]
    setup = 'from __main__ import {}, values'.format(', '.join(funcs))
    for func in funcs:
        print(func)
        print(timeit.timeit(
            '{}(values)'.format(func),
            setup=setup,
            number=1000
        ))

我添加了int轉換以確保函數返回相同的內容,並獲得以下結果:

str_method
1.1685157899992191
list_method
2.6124089090008056
set_method
0.09523714500392089

請注意,如果必須轉換輸入,則在列表中搜索比在字符串中搜索要快是不正確的:

>>> timeit.timeit('1 in l', setup='l = [9, 8, 7, 6, 5, 4, 3, 2, 1]')
0.15300405000016326
>>> timeit.timeit('str(1) in s', setup='s = "9 8 7 6 5 4 3 2 1"')
0.23205067300295923

反復append荷蘭國際集團到一個列表是不是很有效,因為它意味着基礎對象的頻繁調整大小-列表理解,如所示set的版本,是更有效的。

搜索字符串:

如果不是str(i)

快得多

然后在列表中搜索

如果不是我在distinct_list中:

here are lprofile lines for string search in OP code

Line #      Hits         Time  Per Hit   % Time      Line Contents 


    17     75000     80366013   1071.5     92.7       if not str(i) in distinct_string:
    18     50000      2473212     49.5      2.9                  distinct_string += str(i) + " "

and for list search in OP code

   39     75000    769795432  10263.9     99.1          if not i in distinct_list:
   40     50000      2813804     56.3      0.4              distinct_list.append(i)

我認為存在邏輯缺陷,這使得字符串方法看起來更快。
當匹配長字符串中的子字符串時, in運算符將在包含搜索項的第一個子字符串中過早返回。 為了證明這一點,我讓循環從最高值向后運行到最小,然后只返回原始循環值的50%(我只檢查了結果的長度)。 如果精確匹配,則從頭開始還是從頭開始檢查序列都沒有區別。 我得出的結論是,字符串方法通過在長字符串的開頭附近進行匹配來簡化許多比較。 不幸的是,重復項的特殊選擇掩蓋了這一點。

在第二個測試中,我讓字符串方法搜索" " + str(i) + " "以消除子字符串匹配。 現在,它的運行速度僅比list方法快2倍(但仍然更快)。

@jonrsharpe:關於set_method,我看不到為什么一個人一個接一個地觸摸所有集合元素,而不是像這樣在一個set語句中:

def set_method(values):
    return list(set(values))

這將產生完全相同的輸出,並且在我的PC上運行速度大約快2.5倍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM