我以前在python中使用过字典,但我仍然是python的新手。这次我用的是字典的字典,字典的字典……即三层字典,并且想要在对其进行编程之前进行检查。
我想在这个三层字典中存储所有数据,并且想知道什么是一种很好的pythonic初始化方式,然后读取文件并写入这样的数据结构。
我想要的字典类型如下:
{'geneid':
{'transcript_id':
{col_name1:col_value1, col_name2:col_value2}
}
}数据类型如下:
geneid\ttx_id\tcolname1\tcolname2\n
hello\tNR432\t4.5\t6.7
bye\tNR439\t4.5\t6.7你有什么好办法吗?
谢谢!
发布于 2013-03-01 07:46:19
首先,让我们从csv模块开始处理行的解析:
import csv
with open('mydata.txt', 'rb') as f:
for row in csv.DictReader(f, delimiter='\t'):
print row这将打印以下内容:
{'geneid': 'hello', 'tx_id': 'NR432', 'col_name1': '4.5', 'col_name2': 6.7}
{'geneid': 'bye', 'tx_id': 'NR439', 'col_name1': '4.5', 'col_name2': 6.7}所以,现在你只需要把它重新组织成你喜欢的结构。这几乎是微不足道的,除非您必须处理这样一个事实,即第一次看到给定的geneid时,您必须为其创建一个新的空dict,同样,当您第一次在geneid中看到给定的tx_id时,也必须为它创建一个新的空and。你可以用setdefault来解决这个问题
import csv
genes = {}
with open('mydata.txt', 'rb') as f:
for row in csv.DictReader(f, delimiter='\t'):
gene = genes.setdefault(row['geneid'], {})
transcript = gene.setdefault(row['tx_id'], {})
transcript['colname1'] = row['colname1']
transcript['colname2'] = row['colname2']您可以使用defaultdict使其更具可读性
import csv
from collections import defaultdict
from functools import partial
genes = defaultdict(partial(defaultdict, dict))
with open('mydata.txt', 'rb') as f:
for row in csv.DictReader(f, delimiter='\t'):
genes[row['geneid']][row['tx_id']]['colname1'] = row['colname1']
genes[row['geneid']][row['tx_id']]['colname2'] = row['colname2']这里的诀窍在于,顶级dict是一个特殊的…,每当它第一次看到新的密钥…时,它都会返回一个空的dict并且它返回的空dict本身就是一个空dict。唯一困难的部分是,defaultdict接受返回正确类型对象的函数,而返回defaultdict(dict)的函数必须使用partial、lambda或显式函数编写。( ActiveState上的食谱和PyPI上的模块将为您提供一个更通用的版本,如果您愿意,它可以根据需要创建新的字典。)
发布于 2013-03-01 07:55:58
我也在努力寻找替代方案,并在stackoverflow中得出了这个也很好的答案:
What's the best way to initialize a dict of dicts in Python?
基本上在我的例子中:
class AutoVivification(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value发布于 2014-09-18 10:42:57
我必须在为我的研究编写代码时例行公事地这样做。您将希望使用defaultdict包,因为它允许您通过简单的赋值在任何级别添加key:value对。回答完你的问题后,我会给你看的。这是直接来自我的一个程序。关注最后4行(不是注释),在代码块的其余部分跟踪变量,看看它在做什么:
from astropy.io import fits #this package handles the image data I work with
import numpy as np
import os
from collections import defaultdict
klist = ['hdr','F','Ferr','flag','lmda','sky','skyerr','tel','telerr','wco','lsf']
dtess = []
for file in os.listdir(os.getcwd()):
if file.startswith("apVisit"):
meff = fits.open(file, mode='readonly', ignore_missing_end=True)
hdr = meff[0].header
oid = str(hdr["OBJID"]) #object ID
mjd = int(hdr["MJD5"].strip(' ')) #5-digit observation date
for k,v in enumerate(klist):
if k==0:
dtess = dtess+[[oid,mjd,v,hdr]]
else:
dtess=dtess+[[oid,mjd,v,meff[k].data]]
#header extension works differently from the rest of the image cube
#it's not relevant to populating dictionaries
#HDUs in order of extension no.: header, flux, flux error, flag mask,
# wavelength, sky flux, error in sky flux, telluric flux, telluric flux errors,
# wavelength solution coefficients, & line-spread function
dtree = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
for s,t,u,v in dtess:
dtree[s][t][u].append(v)
#once you've added all the keys you want to your dictionary,
#set default_factory attribute to None
dtree.default_factory = None以下是摘要版本。
(lambda:”(减去引号) n-1次,在末尾粘贴“defaultdict(
如果没有将default_factory设置为None,则可以稍后通过键入my_dictkey_1...=new_value之类的内容或使用append()命令添加到嵌套字典中。您甚至可以添加额外的字典,只要您通过这些赋值形式添加的字典本身不是嵌套的。
*警告!将default_factory属性设置为None的代码片段中新添加的最后一行非常重要。你的电脑需要知道你什么时候添加完你的字典,否则它可能会继续在后台分配内存以防止buffer overflow,直到程序停止为止。这是memory leak的一种类型。在我写了这个答案之后,我以一段艰难的方式学会了这一点。这个问题困扰了我几个月,我甚至不认为我是最后解决这个问题的人,因为我对内存分配一无所知。
https://stackoverflow.com/questions/15147740
复制相似问题