【问题标题】:Multiple dictionary list of values assignment with a single for loop for multiple keys使用单个 for 循环为多个键分配值的多个字典列表
【发布时间】:2019-05-20 15:47:23
【问题描述】:

我想在 Python3 中使用单个 for 循环创建一个字典,其中包含多个键的值列表。对我来说,执行时间和内存占用至关重要,因为我的 Python3 脚本正在读取的文件相当长。

我已经尝试过以下简单的脚本:

p_avg = []
p_y = []
m_avg = []
m_y = []
res_dict = {}

with open('/home/user/test', 'r') as f:
    for line in f: 
        p_avg.append(float(line.split(" ")[5].split(":")[1]))
        p_y.append(float(line.split(" ")[6].split(":")[1]))
        m_avg.append(float(line.split(" ")[1].split(":")[1]))
        m_avg.append(float(line.split(" ")[2].split(":")[1]))

res_dict['p_avg'] = p_avg
res_dict['p_y'] = p_y
res_dict['m_avg'] = m_avg
res_dict['m_y'] = mse_y

print(res_dict)

我的home/user/test文件的格式是:

n:1 m_avg:7588.39 m_y:11289.73 m_u:147.92 m_v:223.53 p_avg:9.33 p_y:7.60 p_u:26.43 p_v:24.64
n:2 m_avg:7587.60 m_y:11288.54 m_u:147.92 m_v:223.53 p_avg:9.33 p_y:7.60 p_u:26.43 p_v:24.64
n:3 m_avg:7598.56 m_y:11304.50 m_u:148.01 m_v:225.33 p_avg:9.32 p_y:7.60 p_u:26.43 p_v:24.60
.
.
.

上面显示的 Python 脚本有效,但首先它太长且重复,其次,我不确定它的效率如何。我最终想用列表理解来创建相同的内容。类似的东西:

(res_dict['p_avg'], res_dict['p_y']) = [(float(line.split(" ")[5].split(":")[1]), float(line.split(" ")[6].split(":")[1])) for line in f]

但是对于所有四个字典键。你认为使用列表推导可以减少脚本使用的内存占用和执行速度吗?列表理解的正确语法应该是什么?

[编辑] 我已经更改了 dict -> res_dict,因为有人提到这不是一个好习惯,我还修复了一个错字,其中 p_y 没有指向正确的值并添加了一条打印语句来打印其他用户提到的结果字典。

【问题讨论】:

  • 请添加示例输入并检查问题中的缩进。此外,我没有看到print 或任何你如何得到输出的东西。请也解决这个问题。
  • 您问题中的代码不会执行,因为没有定义mse_y 变量。您也不应该为变量提供与dict 等内置函数相同的名称。一个相当明显的优化是不将同一行拆分 4 次,但看起来你完全没有努力自己优化。我还建议您在尝试优化脚本之前先分析您的脚本,以查看它在哪里花费了大部分执行时间。见How can you profile a Python script?

标签: python python-3.x dictionary list-comprehension


【解决方案1】:

您可以使用defaultdict。无需每次都拆分行,为了使其更具可读性,您可以使用 lambda 提取每个项目的字段。

from collections import defaultdict

res = defaultdict(list)

with open('/home/user/test', 'r') as f:
    for line in f: 
        items = line.split()
        extract = lambda x: x.split(':')[1]

        res['p_avg'].append(extract(items[5]))
        res['p_y'].append(extract(items[6]))
        res['m_avg'].append(extract(items[1]))
        res['m_y'].append(extract(items[2]))

【讨论】:

  • 我同意拆分行最初是有意义的,但是不可能用一行来分配所有键的值
【解决方案2】:

您可以初始化 dict 以包含字符串/列表对,然后在遍历每一行时直接附加。此外,您不想在每次迭代中一直在 line 上调用 split()。相反,只需调用一次并保存到本地变量并从此变量索引。

# Initialize dict to contain string key and list value pairs
dictionary = {'p_avg':[],
              'p_y':[],
              'm_avg':[],
              'm_y':[]
             }
with open('/home/user/test', 'r') as f:
    for line in f:
        items = line.split() # store line.split() so you don't split multiple times per line
        dictionary['p_avg'].append(float(items[5].split(':')[1]))
        dictionary['p_y'].append(float(items[6].split(':')[1])) # I think you meant index 6 here
        dictionary['m_avg'].append(float(items[1].split(':')[1]))
        dictionary['m_y'].append(float(items[2].split(':')[1]))

【讨论】:

  • 是的,您对字典名称的看法是正确的,是的,我的意思是索引 6。我已经简化了我的程序并打错了。
【解决方案3】:

你可以预先定义字典属性:

d = {
    'p_avg': [],
    'p_y': [],
    'm_avg': [],
    'm_y': []
}

然后直接附加到它们:

with open('/home/user/test', 'r') as f:
    for line in f:
        splitted_line = line.split(" ")
        d['p_avg'].append(float(splitted_line[5].split(":")[1]))
        d['p_y'].append(float(splitted_line[5].split(":")[1]))
        d['m_avg'].append(float(splitted_line[1].split(":")[1]))
        d['m_avg'].append(float(splitted_line[2].split(":")[1]))

附:切勿使用等于内置词的变量名称,如dictlist 等。这可能会导致许多不同的错误!

【讨论】:

    猜你喜欢
    • 2017-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-29
    • 1970-01-01
    • 2020-08-29
    相关资源
    最近更新 更多