【问题标题】:What is the best way to create a python dictionary from a string?从字符串创建 python 字典的最佳方法是什么?
【发布时间】:2015-11-07 16:17:19
【问题描述】:

我有一个大文件,我将在其中解析大约 1.9E8 行。

在每次迭代期间,我将创建一个临时字典以发送到另一个方法,这将为我提供我想要的输出。

由于文件太大,用readlines()方法打不开。

所以我最后的办法是在解析过程中让它更快。

我已经有两个用于生成字典的选项。 optionBoptionA 具有更好的性能,我知道我可以尝试正则表达式,但是我不熟悉它。如果有更好的替代方案,我愿意获得见解。

预期输入:"A@1:100;2:240;...:.."输入可能更长,它可以有更多组和频率

def optionA(line):
    _id, info = line.split("@")
    data = {}
    for g_info in info.split(";"):
        k, v = g_info.split(":")
        data[k] = v
    return data

def optionB(line):
    _id, info = line.split("@")
    return dict(map(lambda i: i.split(":"), info.split(";")))

预期输出: {'1': '100', '2': '240'}

我愿意接受任何推荐!

【问题讨论】:

  • 你的正则表达式有多好?
  • 如果文件太大以至于读取它已经是一个问题,那么是什么让您认为将所有数据都放在内存字典中会更好?
  • @poke,请再仔细阅读一遍。 我将创建一个临时字典以发送到另一个方法。该字典将作为方法的输入。
  • 为什么两个版本不只使用timeit
  • @poke,OP 正在逐行处理。听起来临时字典一次只存在一行。 OP 并未将所有行的所有字典都存储在内存中。

标签: python regex dictionary


【解决方案1】:

解析行的正则表达式的快速示例:

>>> import re
>>> line = 'A@1:100;2:240'
>>> data = re.search(r'@(\d+):(\d+);(\d+):(\d+)',line).groups()
>>> D = {data[0]:data[1],data[2]:data[3]}
>>> D
{'1': '100', '2': '240'}

以下是一些时间安排:

import re
regex = re.compile(r'@(\d+):(\d+);(\d+):(\d+)')

def optionA(line):
    _id, info = line.split("@")
    data = {}
    for g_info in info.split(";"):
        k, v = g_info.split(":")
        data[k] = v
    return data

def optionB(line):
    _id, info = line.split("@")
    return dict(map(lambda i: i.split(":"), info.split(";")))

def optionC(line):
    data = regex.search(line).groups()
    return {data[0]:data[1],data[2]:data[3]}

line = 'A@1:100;2:240'

次:

C:\>py -m timeit -s "import x" "x.optionA(x.line)"
100000 loops, best of 3: 3.01 usec per loop

C:\>py -m timeit -s "import x" "x.optionB(x.line)"
100000 loops, best of 3: 5.15 usec per loop

C:\>py -m timeit -s "import x" "x.optionC(x.line)"
100000 loops, best of 3: 2.88 usec per loop

编辑:随着需求的细微变化,我尝试了optionCfindalloptionA 略有不同的版本:

import re
regex = re.compile(r'(\d+):(\d+)')

def optionA(line):
    _id, info = line.split("@")
    data = {}
    for g_info in info.split(";"):
        k, v = g_info.split(":")
        data[k] = v
    return data

def optionAA(line):
    data = {}
    for g_info in line[2:].split(";"):
        k, v = g_info.split(":")
        data[k] = v
    return data

def optionB(line):
    _id, info = line.split("@")
    return dict(map(lambda i: i.split(":"), info.split(";")))

def optionC(line):
    return dict(regex.findall(line))

line = 'A@1:100;2:240;3:250;4:260;5:100;6:100;7:100;8:100;9:100;10:100'

时间安排:

C:\>py -m timeit -s "import x" "x.optionA(x.line)"
100000 loops, best of 3: 8.35 usec per loop

C:\>py -m timeit -s "import x" "x.optionAA(x.line)"
100000 loops, best of 3: 8.17 usec per loop

C:\>py -m timeit -s "import x" "x.optionB(x.line)"
100000 loops, best of 3: 12.3 usec per loop

C:\>py -m timeit -s "import x" "x.optionC(x.line)"
100000 loops, best of 3: 12.8 usec per loop

所以看起来修改后的optionAA 在这条特定的行中获胜。希望这表明测量算法的重要性。我很惊讶findall 速度变慢了。

【讨论】:

  • 嗯,我喜欢你的选择。我只需要看看它对两个以上组的表现如何,我的意思是,以防line = 'A@1:100;2:240;3:122;...'
  • @RicardoSilveira 您的问题中必须指定更长输入的可能性。
  • @RicardoSilveira, dict(re.findall(r'(\d+):(\d+)',line)) 将是查找所有配对的快速方法,但您确实应该根据该要求更新您的问题。
  • 对不起,我刚刚更新了它。这是因为当我写选项 A 和 B 时,我想我已经明确表示它可能会更长。
  • @RicardoSilveira,我用更长的线做了一些计时。见编辑。
【解决方案2】:

这是一个使用已编译的正则表达式匹配您的模式的简单示例。

import re

s = "A@1:100;2:240"
compiledre = re.compile("A@(\d+):(\d+);(\d+):(\d+)$")
res = compiledre.search(s)
if res:
    print dict([(res.group(1),res.group(2)),(res.group(3),res.group(4))])

输出是:

{'1': '100', '2': '240'}

【讨论】:

    猜你喜欢
    • 2011-09-16
    • 2019-06-11
    • 2011-01-18
    • 2011-02-13
    • 1970-01-01
    • 2023-03-05
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多