【问题标题】:Read/Write a file where every row is a list for/from a dict读/写一个文件,其中每一行都是字典的列表
【发布时间】:2015-11-11 23:12:01
【问题描述】:

我想基本上做到这一点:

  f = open(genes_path, 'w')
  for key, genes in key_genes.iteritems():
      f.write(key)
      for gene in genes:
          f.write(",\t"+gene)
      f.write("\n")

  f.close()

得到这个:

key1、AT3G32920、AT3G33187、AT3G32940、AT3G32930、AT3G32980、AT3G32960

key2、AT3G32920、AT3G33187、AT3G32940、AT3G32930、

键可以是任何字符串(不带逗号),顺序在任何地方都无关紧要(我使用来自boltons 的 OrderedMultiDict 和列表以方便打印,但它真的没关系,可以是 dict 和设置为我所关心的),每行可以有不同数量的元素。

我似乎找不到任何可以完成这项非常简单任务的模块。 DictWriter 需要列/字段名称,因此this 无法回答我的问题。 Numpy 仅适用于矩形数组,并且填充引入了太多不必要的东西。我知道自己编写循环很容易,但我只是觉得这很常见,它会有自己的内置函数。

有时我只需要向人们发送大量事物列表(例如基因给不会编程的人),以便他们可以将其拉入 excel 添加或删除元素,然后将其发送回去,而我不必这样做还有什么。

有人知道有一个模块可以自动读取和写入这些乱七八糟的 dict-of-lists 文件吗?或者如果有充分的理由不存在这种情况?

我在想像pandas.read_csv(path, delimiter=",")pandas.DataFrame.to_csv(path, delimiter=",") 这样简单的东西。


基本原理

我之所以挑剔它是一个模块的单个功能,而不是我可以在纯 python 中非常轻松做到的事情,不是因为我很懒,而是因为当你使用来自具有良好文档的模块的某些内容对于某人来说更容易查看代码并准确了解其意图。即使任务是微不足道的,您仍然可以降低代码的复杂性。我认为编写自己的函数是特定于域的,而一个常见的读写例程应该是你import 的东西,如果有的话最好使用。 python 禅宗的一部分对吗?所以第二个问题真的是问“这是一项特定于域的任务吗?”,因为在我看来并非如此。

【问题讨论】:

  • 您是否尝试过使用csv module
  • @Two-BitAlchemist 那是 DictWriter 的来源,所以是的。
  • @sodiumnitrate 我不想明确写入 excel 格式,我想要 csv/text,因为这是通用的。
  • 我的意思是,那么你正在做的应该工作。我会编写一个执行打印的函数,使用下面 Jake Griffin 的答案或您的代码,并在您需要打印某些内容时调用它。

标签: python dictionary io


【解决方案1】:

您可以将每一行构建成一个字符串并进行一次写入:

with open(genes_path, 'w') as f:
    for key, genes in key_genes.iteritems():
        f.write("\n".join(",\t".join([key] + genes)))

这个还是自己做的,不过比你贴的代码更简洁。

【讨论】:

  • 你不是我想要的。我想这也会带来很好的加速效果。
【解决方案2】:

一方面,我看不出你的原始循环有什么不好(你可以把它变成一个函数,并使用with context manager 缩短)。但是,我提到了 csv 模块,因为它似乎几乎完全满足您的要求,不需要 DictWriter

我假设你是从这样开始的:

In [4]: key_genes
Out[4]: 
{'key1': ['AT3G32920',
  'AT3G33187',
  'AT3G32940',
  'AT3G32930',
  'AT3G32980',
  'AT3G32960'],
 'key2': ['AT3G32920', 'AT3G33187', 'AT3G32940', 'AT3G32930'],
 'key3': ['AT3G32920',
  'AT3G33187',
  'AT3G32940',
  'AT3G32930',
  'AT3G32980',
  'AT3G32960'],
 'key4': ['AT3G32920', 'AT3G33187', 'AT3G32940', 'AT3G32930']}

所以这段代码:

with open('out.csv', 'wb') as outfile:
    writer = csv.writer(outfile)
    for key, genes in key_genes.iteritems():
        writer.writerow([key] + genes)

产生这个:

key3,AT3G32920,AT3G33187,AT3G32940,AT3G32930,AT3G32980,AT3G32960
key2,AT3G32920,AT3G33187,AT3G32940,AT3G32930
key1,AT3G32920,AT3G33187,AT3G32940,AT3G32930,AT3G32980,AT3G32960
key4,AT3G32920,AT3G33187,AT3G32940,AT3G32930

显然如果您希望对键进行排序,您可以这样做您的键将被排序,因为您使用的是有序结构,而我使用的是常规的内置字典。现在这就是我们进入您要求的几乎部分的地方。您使用 ,\t 作为分隔符。如果您尝试使用csv.writer 执行此操作,它会抱怨分隔符应该是一个字符。这对我来说很有意义,因为 csv 文件通常是逗号分隔或制表符分隔的,而不是两者兼而有之。分隔符只是为了便于机器处理而存在,并且机器只需要一个字符(在其他任何地方都不会出现未引用的字符)来执行此操作。

所以我的最终答案是:如果您可以使用单字符分隔符(对于正常的 CSV 处理,这应该不是问题),请使用 csv 模块。否则,请使用您的短循环。

【讨论】:

  • 这也很好,但就像你说的那样,就冗长而言,这并不是一个巨大的改进。分隔符不/不应该真的很重要。我将把我的想法的函数签名放在问题中。
猜你喜欢
  • 2016-03-07
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 2023-01-29
  • 1970-01-01
  • 2017-01-04
  • 2021-05-19
  • 1970-01-01
相关资源
最近更新 更多