3

次のようなテキスト ファイル内のグリッドを想像してください。

  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 から離れていました。もっと良い方法はありますか? おそらく、ネストされた辞書は実際には最善の方法ではないでしょうか?

更新:

  1. 残念ながら、これをバニラのpythonで行う必要があるため、外部ライブラリ(私が好きだと信じている)を使用することはできません
  2. サンプル コード フォームの疑似コードを実際のコードに更新しました。恥ずかしそうに頭を垂れる。
4

1 に答える 1

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()
    

    Pythonwith-block. _ を使用withすると、ファイルハンドルを閉じるのを忘れることはありません。また、例外が発生した場合でも、with-block.

  • f.readlines()一般的には、できれば避けたほうがよいでしょう。これにより、ファイル全体がリストに丸呑みされます。特にファイルが巨大な場合、これはメモリに負担がかかる可能性があります。いつもの

    with open(...) as f:
        for line in f:
    

    代わりに使用できます。

  • collections.default(dict)を 作成matrixすると、デフォルトで になります。したがって、初期化をスキップできます。matrix[field]dict

    for key in keys:
        matrix[key] = {}
    
  • Adefaultdictは のサブクラスなdictので、 a と同じように使用できますdict。印刷方法が気に入らない場合、または空の dict をfor anyにmatrix自動的に割り当てるの をやめたい場合は、次の方法でdefaultdict を通常の辞書に戻すことができます。matrix[key]keydict

    matrix = dict(matrix)
    
  • 可能であれば、数値インデックスを使用しないでくださいfor-loops

    for i, c in enumerate(chars[1:]):
    

    これはほとんどの C ライクな言語では必須ですが、Python にはより良い方法があります: 項目自体をループすることです:

    for col, val in zip(columns, vals):
    

    これにより、変数名が実際に関心のあるオブジェクトに割り当てられるため、コードが読みやすくなります。インデックスだけでなく、keys[i-1]. また、 で行われているように、インデックスを 1 つずつ調整する必要がある場合に発生する可能性のある「1 つずれた」エラーを回避するのにも役立ちますkeys[i-1]


もう 1 つの可能性は、ネストされた dict ではなく、キーとして 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}}
于 2013-03-01T02:07:28.703 に答える