【问题标题】:Reading from file using dict comprehensions使用 dict 理解从文件中读取
【发布时间】:2016-02-05 16:16:18
【问题描述】:

我经常需要从(通常是制表符分隔值)文件中读取数据并将它们转换为字典。通常我只需要将其中一列映射到另一列,但也可能对值进行一些处理(例如剥离空白)。我一直在尝试提出一个 dict 理解模式来做到这一点,但我一直遇到一些小麻烦,这使我无法始终如一地以最简洁和易于理解的方式实施它。而且我感觉可能有更好的方法。

以下是我尝试过的(一些)方法,以及它们出错的地方:


打开(路径)为 f: 返回 {line.split("\t")[0].strip(): line.split("\t")[1].strip() 对于 f} 中的行

这是我经常使用的。它允许我修改键和值,并且可以在任何列上工作(例如,如果我想将值从第三列映射到第一列)。明显的问题是line.split() 部分的重复。有没有办法将line.split("\t") 绑定到一个临时变量,或者将值直接解包到变量中?


打开(路径)为 f: return dict(line.split("\t")[:2] for line in f)

我刚想出这个。它适用于这个简单的情况(只是将第一列映射到第二列,没有任何处理),但不能推广到其他情况。很难进行额外的处理,并且使用的列必须相邻。它也不是一个严格的dict理解,因为它使用切片,所以不能变成一个。


d = 字典() 对于打开(路径)中的行: d.update({line.split("\t")[0]: line.split("\t")[1]}) 返回 d

当然,我可以先创建字典,然后更新每一行。但是现在我要创建dict并单独返回,代码重复仍然存在。


我也玩过嵌套的dict理解并将分割的行解压缩为变量,但遇到了不同的问题。

【问题讨论】:

  • 您正在尝试优化可能受 I/O 限制的内容,因此只要创建字典尽可能快或使用最少的代码,您所做的任何事情都不会产生很大的影响.

标签: python dictionary dictionary-comprehension


【解决方案1】:

您可以通过在您的 f 周围放一些东西来做到这一点:

def tabsplit(file_object):
    for line in file_object:
        yield line.split("\t")

然后:

with open(path) as f:
    return {left.strip(): right.strip() for left, right, *rest in tabsplit(f)}

【讨论】:

  • 有趣,我没有尝试过以任何方式使用生成器...但是,这就是我之前暗示的解包问题发挥作用的地方。输入文件可能包含不同数量的选项卡 - 例如,可能存在属于最后一列的尾随值。然后这些文件会抛出一个 ValueError,我不知道如何在 dict 理解中处理它。这些文件通常还包含不需要在字典中的其他列 - 通过将它们解压缩到 _, _, ... 来忽略它们可能是可能的,但我也觉得这不是很优雅。
  • 所以你想忽略除前两列之外的每一列?查看我的编辑以丢弃*rest
【解决方案2】:

不知道为什么先创建字典不起作用

result = {}
with open(path) as f:
    for line in f:
        columns = line.split("\t")
        key = columns[0] # first item is the key right?
        result[key] = columns[1]

【讨论】:

  • 当然它确实有效,但我试图让它尽可能简洁。这就是为什么我不喜欢单独的声明和返回步骤——即使这将是最易读的解决方案之一。
  • @Sebastian:简洁并不总是 == 更好。可读性和可维护性非常重要,而效率通常并不重要……就像 97% 的时间一样。见When to optimize
  • @martineau 我知道,这正是我问这个问题的原因。找到一个我始终可以使用的代码模式将使我能够始终如一地使用它,从而提高长期的可维护性和可理解性。如果我能找到行数更少的模式,我可能会更喜欢它,因为它的滚动更少——我倾向于在 IPython 笔记本中工作,而且额外的行加起来很快......
  • @Sebastian:这两个答案都做得很好。为了最大限度地减少行数,使其成为实用函数......类似于 L3viathan 所做的,但更高级别。将任务拆分为多个块通常会在很多方面有所帮助。
猜你喜欢
  • 2015-06-25
  • 2020-06-24
  • 1970-01-01
  • 2020-09-05
  • 1970-01-01
  • 1970-01-01
  • 2016-04-28
  • 2021-02-10
  • 1970-01-01
相关资源
最近更新 更多