代码之家  ›  专栏  ›  技术社区  ›  earl

Python中字符串到整数的快速转换

  •  3
  • earl  · 技术社区  · 17 年前

    实际上,一个简单的问题是:在TSV(制表符分隔值)文件中,有10亿(1e+9)个无符号32位整数存储为十进制ASCII字符串。转换使用 int()

    因此,问题是:在Python中,将字符串转换为整数的最快方法是什么?

    array.array 在他的 "Optimization Anecdote" .

    (选项卡扩展为空格)

    38262904        "pfv"              2002-11-15T00:37:20+00:00
    12311231        "tnealzref"        2008-01-21T20:46:51+00:00
    26783384        "hayb"             2004-02-14T20:43:45+00:00
    812874          "qevzasdfvnp"      2005-01-11T00:29:46+00:00
    22312733        "bdumtddyasb"      2009-01-17T20:41:04+00:00
    

    微基准

    以下所有语言都是解释语言。主机正在运行64位Linux。

    Python为0.9.1的Python 2.6.2,每秒约214k次转换(100%):

    In [1]: strings = map(str, range(int(1e7)))
    
    In [2]: %timeit map(int, strings);
    10 loops, best of 3: 4.68 s per loop
    

    REBOL 3.0版本2.100.76.4.2,~231kcps(108%):

    >> strings: array n: to-integer 1e7 repeat i n [poke strings i mold (i - 1)]
    == "9999999"
    
    >> delta-time [map str strings [to integer! str]]
    == 0:00:04.328675
    

    正如John在评论中指出的,这个版本确实如此 构建一个已转换整数的列表,以便给定的速度比相对于Python的4.99s运行时 for str in strings: int(str) .

    >> delta-time: func [c /local t] [t: now/time/precise do c now/time/precise - t]
    
    >> strings: array n: to-integer 1e7 repeat i n [poke strings i mold (i - 1)]
    == "9999999"
    
    >> delta-time [foreach str strings [to integer! str]]
    == 0:00:01.913193
    

    KDB+2.6t 2009.04.15,~2016kcps(944%):

    q)strings:string til "i"$1e7
    
    q)\t "I"$strings
    496
    
    7 回复  |  直到 17 年前
        1
  •  4
  •   earl    17 年前

    以下最简单的C扩展已经大大改进了内置的功能,每秒转换的字符串数是原来的三倍(650kcps比214kcps):

    static PyObject *fastint_int(PyObject *self, PyObject *args) {
        char *s; unsigned r = 0;
        if (!PyArg_ParseTuple(args, "s", &s)) return NULL;
        for (r = 0; *s; r = r * 10 + *s++ - '0');
        return Py_BuildValue("i", r);
    }
    

    这显然不适用于任意长度的整数和其他各种特殊情况,但在我们的场景中这并没有问题。

        2
  •  3
  •   Peter Shinners    17 年前

    通过确保在最紧密的循环中只使用“局部”变量,您将获得一定的速度百分比。这个 int 函数是全局函数,因此查找它比查找本地函数要昂贵。

    你真的需要在任何时候都存储所有的十亿数字吗。考虑使用一些迭代器一次只给你几个值,十亿个数字会占用一点存储空间。将这些附加到一个列表中,一次一个,将需要几次大规模的重新分配。

    如果可能的话,让你的循环完全脱离Python。这里的地图功能可以是您的朋友。我不确定你的数据是如何存储的。如果每行只有一个数字,您可以将代码减少到

    values = map(int, open("numberfile.txt"))
    

    如果每行有多个空格分隔的值,那么深入研究itertools以避免Python中的循环代码。此版本还具有创建数字迭代器的附加好处,因此一次只能从文件中输出一个或多个数字,而不是一次10亿。

    numfile = open("numberfile.txt")
    valIter = itertools.imap(int, itertools.chain(itertools.imap(str.split, numfile)))
    
        3
  •  2
  •   Greg Hewgill    17 年前

    我可能会建议,对于原始速度,Python并不是完成此任务的合适工具。手工编码的C实现将轻松击败Python。

        4
  •  1
  •   ramosg    17 年前

    Psyco library 或者用低级语言(如C/C++)编写应用程序。

        5
  •  1
  •   Jim Dennis    17 年前

    正如其他人所说,您可以编写自己的C模块来为您进行解析/转换。然后你可以简单地导入它并调用它。您可能能够使用Pyrex或其Cython衍生物从Python生成C(通过向Python添加一些类型约束提示)。

    Cython 看看这是否有帮助。

    不过我想到的另一个问题是。。。你打算用这十亿个整数做什么?是否可能将它们作为字符串加载、作为字符串搜索并根据需要执行延迟转换?或者你可以使用 threading 或 multiprocessing 模块和队列?(让一个或多个线程/进程执行转换并向处理引擎从中获取它们的队列提供数据)。换言之,生产者/消费者的设计会缓解这个问题吗?

        6
  •  0
  •   Mike Dunlavey    17 年前

    这可能不是你的选择,但我会认真考虑使用二进制文件而不是文本。它经常变化吗?如果没有,您可以对其进行预处理。

        7
  •  0
  •   Max    8 年前

    这是numpy做得很好的事情: