繁体   English   中英

Python:为什么多个列表理解似乎比使用 if...elif 语句的单个 for 循环更快?

[英]Python: why is multiple list comprehensions seemingly faster than a single for loop with if...elif statements?

我有一些代码,我试图确定是否有更快的运行方法。 本质上,我有一个带分隔符的文件,我正在迭代该文件以找到一组标志来解析数据。 这些文件可能很长,所以我试图为此找到一种快速的方法。

我尝试过的两种方法是列表理解和 for 循环:

方法一:

flag_set_1 = [i for i,row in enumerate(data_file) if row[0] == flag_1]
flag_set_2 = [i for i,row in enumerate(data_file) if row[0] == flag_2]
flag_set_3 = [i for i,row in enumerate(data_file) if row[0] == flag_3]
flag_set_4 = [i for i,row in enumerate(data_file) if row[0] == flag_4]

方法二:

for i,row  in enumerate(data_file):
    if row[0] == flag_1:
        flag_set_1.append(i)
    elif row[0] == flag_2:
        flag_set_2.append(i)
    elif row[0] == flag_3:
        flag_set_3.append(i)
    elif row[0] == flag_4:
        flag_set_4.append(i)

在这种情况下,我实际上期望列表理解会变慢。 认为方法 1 必须迭代 data_file 4 次,而方法 2 只需迭代一次。 我怀疑在方法 2 中使用 append() 是减慢速度的原因。

所以我问,有没有更快的方法来实现这个?

没有任何数据样本或基准,也很难重现您的观察结果。 我试过:

from random import randint
data_file = [[randint(0, 15) for _ in range(20)] for _ in range(100000)]
flag_1 = 1
flag_2 = 2
flag_3 = 3
flag_4 = 4

常规循环的速度是四个列表理解的两倍(参见下面的基准)。

如果你想提高这个过程的速度,你有几个线索。

列表理解和常规循环

如果flag_n是字符串并且您确定row[0]是每一row中的其中一个,那么您可以检查一个字符而不是整个字符串。 例如:

flag_1 = "first flag"
flag_2 = "second flag"
flag_3 = "third flag"
flag_4 = "fourth flag"

查看第二个字符: f<I>rst, S<E>cond, T<H>ird, F<O>urth 您只需要检查row[0][1] == 'i' (或'e''h''o' )而不是row[0] == flag_n

常规循环

如果你想提高常规循环的速度,你有几个线索。

在所有情况下

您可以分配flag = row[0]而不是四次获取row[0]的第一个元素。 这是基本的,但它有效。

如果您有关于数据的信息

如果数据按标志排序,您显然可以立即构建flag_n_set :找到第一个最后一个flag_n并编写flag_n_set = list(range(first_flag_n_index, last_flag_n_index+1))

如果你知道标志的频率,你可以命令if... elif... elif... elif... else首先检查更频繁的标志,然后是第二频繁的标志,等等。

您还可以使用 dict 来避免if... elif...序列。 如果您没有太多与任何标志不匹配的行,则可以使用defaultdict

from collections import defaultdict

def test_append_default_dict():
    flag_set = defaultdict(list)

    for i, row  in enumerate(data_file):
        flag_set[row[0]].append(i)

    return tuple(flag_set[f] for f in (flag_1, flag_2, flag_3, flag_4))

以上数据的基准:

test_list_comprehensions    3.8617278739984613
test_append                 1.9978336450003553
test_append_default_dict    1.4595633919998363

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM