1

ネストされた辞書についての方法は次のとおりです。

dicty = dict()
tmp = dict()
tmp["a"] = 1
tmp["b"] = 2
dicty["A"] = tmp

dicty == {"A" : {"a" : 1, "b" : 1}}

問題は、これを大きなファイルに実装しようとしたときに始まり、行ごとに読み取られます。これは、リストの行ごとにコンテンツを出力しています。

['proA', 'macbook', '0.666667']
['proA', 'smart', '0.666667']
['proA', 'ssd', '0.666667']
['FrontPage', 'frontpage', '0.710145']
['FrontPage', 'troubleshooting', '0.971014']

ネストされた辞書で終わりたいと思います(小数を無視します):

{'FrontPage': {'frontpage': '0.710145', 'troubleshooting': '0.971014'},
 'proA': {'macbook': '0.666667', 'smart': '0.666667', 'ssd': '0.666667'}}

行ごとに読んでいるので、上位の辞書に完全な辞書として追加する前に、最初の単語がまだファイル内にあるかどうかを確認する必要があります (それらはすべてグループ化されています)。

これは私の実装です:

def doubleDict(filename):
    dicty = dict()
    with open(filename, "r") as f:
        row = 0
        tmp = dict()
        oldword = ""
        for line in f:
            values = line.rstrip().split(" ")
            print(values)
            if oldword == values[0]:
                tmp[values[1]] = values[2]
            else:
                if oldword is not "":
                    dicty[oldword] = tmp
                tmp.clear()
                oldword = values[0]
                tmp[values[1]] = values[2]
            row += 1
            if row % 25 == 0:
                print(dicty)
                break #print(row)
    return(dicty)

私は実際にこれをパンダに入れたいと思っていますが、今のところ、これが辞書として機能することを嬉しく思います。なんらかの理由で、最初の 5 行だけを読んだ後、次のようになります。

{'proA': {'frontpage': '0.710145', 'troubleshooting': '0.971014'}},

これは明らかに間違っています。なにが問題ですか?

4

2 に答える 2

2

collections.defaultdict()オブジェクトを使用して、ネストされた辞書を自動インスタンス化します。

from collections import defaultdict

def doubleDict(filename):
    dicty = defaultdict(dict)
    with open(filename, "r") as f:
        for i, line in enumerate(f):
            outer, inner, value = line.split()
            dicty[outer][inner] = value
            if i % 25 == 0:
                print(dicty)
                break #print(row)
    return(dicty)

enumerate()ここで行数を生成していました。別のカウンターを動かし続けるよりもはるかに簡単です。

がなくてもdefaultdict、外側の辞書にネストされた辞書への参照を保持させ、values[0];を使用して再度取得することができます。temp参照を保持する必要はありません。

>>> dicty = {}
>>> dicty['A'] = {}
>>> dicty['A']['a'] = 1
>>> dicty['A']['b'] = 2
>>> dicty
{'A': {'a': 1, 'b': 1}}

defaultdictそうすれば、ネストされた辞書を既に作成しているかどうかをテストする必要がなくなります。それ以外の:

if outer not in dicty:
    dicty[outer] = {}
dicty[outer][inner] = value

キーがまだ存在しない場合は、新しい辞書を作成するため、単にifテストを省略します。defaultdict

于 2013-10-05T23:16:28.783 に答える
1

これは理想的な方法ではありませんが、ほぼ確実に機能します。

あなたの主な問題は、同じtmp辞書を再利用していることです。dicty最初のキーの下に挿入した後、clearそれを新しい値で埋め始めます。これを修正するには、に置き換えtmp.clear()て、すべてのキーに対して同じ辞書を使用するのではなく、キーごとに異なる辞書を作成します。tmp = {}

2番目の問題は、最後tmpに到達したときに最後の値を辞書に保存していないため、ループのdicty[oldword] = tmp後に別の値を追加することです。for

3 番目の問題は、チェックしていることですif oldword is not "":。空の文字列であっても、同等ではなく同一性を比較しているため、これは真実かもしれません。それを に変更するだけif oldword:です。(これは、小さな文字列は通常インターンされ、通常は ID を共有するため、通常は問題ありませんが、それを当てにするべきではありません。)

これらの両方を修正すると、次のようになります。

{'FrontPage': {'frontpage': '0.710145', 'troubleshooting': '0.971014'},
 'proA': {'macbook': '0.666667', 'smart': '0.666667', 'ssd': '0.666667'}}

その形式は有効な辞書でさえないため、これをあなたが主張する形式に変換する方法がわかりません。しかし、うまくいけば、これであなたが近づくことができます。


これを行うには、次の 2 つの簡単な方法があります。

  • などで値をitertools.groupbyグループ化し、各グループを dict に変換して、すべてを 1 ステップで挿入します。これは、既存のコードと同様に、入力が によって既にバッチ処理されている必要がありますvalues[0]
  • 辞書を辞書として使用します。入ってきた各キーを調べて、見つかった場合は値に追加し、見つからない場合は新しいキーを作成できます。Adefaultdictまたはsetdefaultメソッドはこれを簡潔にしますが、それらについて知らなくても、明示的に書き出すのは非常に簡単であり、現在のものよりも冗長ではありません.

2 番目のバージョンは、Martijn Pieters の回答で既に非常にうまく説明されています。

1 つ目は次のように記述できます。

def doubleDict(s):
    with open(filename, "r") as f:
        rows = (line.rstrip().split(" ") for line in f)
        return {k: {values[1]: values[2] for values in g}
                for k, g in itertools.groupby(rows, key=operator.itemgetter(0))}

もちろん、25 行ごとに dict を出力するわけではありませんが、理解を明示的なループに変えることで簡単に追加できます (理想的には、明示的なカウンターenumerateを保持する代わりに使用します)。row

于 2013-10-05T23:22:56.077 に答える