【问题标题】:Python: why is multiple list comprehensions seemingly faster than a single for loop with if...elif statements?Python:为什么多个列表推导似乎比带有 if...elif 语句的单个 for 循环更快?
【发布时间】:2020-08-08 05:16:12
【问题描述】:

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

我尝试过的两种方法是列表推导和 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() 会减慢它的速度。

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

【问题讨论】:

标签: python for-loop list-comprehension


【解决方案1】:

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

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 at 一次:找到第一个最后一个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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2016-02-16
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多