想象一下像这样的文本文件中的网格:
A B C
A 0 1 2
B 3 0 5
C 6 7 0
在python中将其转换为字典的最好方法是:
{
'A': {'A': 0, 'B':3, 'C':6},
'B': {'A': 1, 'B':0, 'C':7},
'B': {'A': 2, 'B':5, 'C':0}
}
所以我可以通过以下方式访问单元格:
matrix['A']['B'] # 3
我目前确实有一些非常粗略的代码(请不要过于严厉地评价我):
matrix = {}
f = open(filepath, 'r')
lines = f.readlines()
keys = lines[0].split()
for key in keys:
matrix[key] = {}
for line in lines[1:]:
chars = line.split()
key_a = chars[0]
for i, c in enumerate(chars[1:]):
key_b = keys[i-1]
matrix[key_a][key_b] = int(c)
print matrix
# Outputs {'A': {'A': 1, 'C': 0, 'B': 2}, 'C': {'A': 7, 'C': 6, 'B': 0}, 'B': {'A': 0, 'C': 3, 'B': 5}}
虽然这没有错,但我已经花了很长时间远离python,有更好的方法吗?也许嵌套字典实际上不是最好的方式?
更新:
答案 0 :(得分:4)
您的代码是合理的,但这里有另一种选择:
import collections
with open('grid_file.txt', 'r') as f:
columns = next(f).split()
matrix = collections.defaultdict(dict)
for line in f:
items = line.split()
row, vals = items[0], items[1:]
for col, val in zip(columns, vals):
matrix[col][row] = int(val)
print(matrix)
产生
defaultdict(<type 'dict'>, {'A': {'A': 0, 'C': 6, 'B': 3}, 'C': {'A': 2, 'C': 0, 'B': 5}, 'B': {'A': 1, 'C': 7, 'B': 0}})
一些提示:
使用
with open(...) as f
...
而不是
f = open(...)
f.close()
因为Python离开时file handle is closed for you
with-block
。使用with
,您永远不会忘记关闭文件句柄,即使发生异常,文件句柄仍会在离开with-block
时关闭。
一般来说,如果可以,最好避免使用f.readlines()
。这个
将整个文件粘贴到列表中。这对记忆来说很麻烦,
特别是如果文件很大。一般
with open(...) as f:
for line in f:
可以改为使用。
如果您将matrix
设为collections.default(dict),那么
默认情况下,matrix[field]
将为dict
。所以你可以跳过
初始化:
for key in keys:
matrix[key] = {}
defaultdict
是dict
的子类,所以你可以非常使用它
和dict
一样。如果你不喜欢它打印或会的方式
喜欢阻止matrix
自动分配空字典
对于任何matrix[key]
key
,您可以将defaultdict转换回
常规dict
:
matrix = dict(matrix)
如果可以,请避免在for-loops
中使用数字索引。
for i, c in enumerate(chars[1:]):
虽然对于大多数类C语言来说这是 de rigueur ,但Python有一个 更好的方法:循环遍历项目本身:
for col, val in zip(columns, vals):
这使代码更具可读性,因为它分配了一个变量名
到你真正感兴趣的对象,而不仅仅是索引
然后你必须撰写像keys[i-1]
这样的东西。它也有帮助
你可以避免在必须调整时出现的“一个一个”的错误
索引一,如keys[i-1]
中所做的那样。
另一种可能性是不使用嵌套的dicts,而是使用2元组(列,行)作为键:
with open('grid_file.txt', 'r') as f:
columns = next(f).split()
matrix = {}
for line in f:
items = line.split()
row, vals = items[0], items[1:]
for col, val in zip(columns, vals):
matrix[col, row] = int(val)
print(matrix)
产量
{('B', 'C'): 7, ('A', 'A'): 0, ('B', 'B'): 0, ('B', 'A'): 1, ('C', 'A'): 2, ('C', 'B'): 5, ('C', 'C'): 0, ('A', 'B'): 3, ('A', 'C'): 6}
然后你可以像这样访问矩阵中的(列,行):
print(matrix['A','C'])
# 6
顺便说一句,如果您安装pandas:
import pandas as pd
import io
text = '''\
A B C
A 0 1 2
B 3 0 5
C 6 7 0'''
df = pd.read_table(io.BytesIO(text), sep='\s+')
print(df.to_dict())
产量
{'A': {'A': 0, 'B': 3, 'C': 6},
'B': {'A': 1, 'B': 0, 'C': 7},
'C': {'A': 2, 'B': 5, 'C': 0}}