-1

ファイルドキュメントの行を読み取り、コードがそれらを整理するコードに取り組んできました。しかし、ある時点で行き詰まり、友人が私に何が使えるか教えてくれました。コードは機能しますが、下から7行目と8行目で彼が何をしているのかわからないようです。私は #### を使用したので、皆さんはそれがどの行であるかを知っています。

では、本質的に、これら 2 行のコードをどのように書き直すことができ、なぜ機能するのでしょうか? sys import argv からの辞書を理解していないようです

filename = input("Please enter the name of a file: ")
file_in=(open(filename, "r"))

print("Number of times each animal visited each station:")
print("Animal Id             Station 1              Station 2")

animaldictionary = dict()

for line in file_in:
    if '\n' == line[-1]:
        line = line[:-1]
    (a, b, c) = line.split(':')
    ac = (a,c)
    if ac not in animaldictionary:
        animaldictionary[ac] = 0
    animaldictionary[ac] += 1

alla = []
for key, value in animaldictionary:
    if key not in alla:
        alla.append(key)
print ("alla:",alla)
allc = []
for key, value in animaldictionary:
    if value not in allc:
        allc.append(value)    
print("allc", allc)

for a in sorted(alla):
    print('%9s'%a,end=' '*13)
    for c in sorted(allc):
        ac = (a,c)
        valc = 0
        if ac in animaldictionary:
            valc = animaldictionary[ac]
        print('%4d'%valc,end=' '*19)

    print()

print("="*60)
print("Animals that visited both stations at least 3 times: ")

for a in sorted(alla):
    x = 'false'
    for c in sorted(allc):
        ac = (a,c)
        count = 0
        if ac in animaldictionary:
            count = animaldictionary[ac]
            if count >= 3:
                x = 'true'
    if x is 'true':    
        print('%6s'%a, end=' ')
        print("")

print("="*60)
print("Average of the number visits in each month for each station:")

#(alla, allc) = 
#for s in zip(*animaldictionary.keys()):
#    (alla,allc).append(s)
#print(alla, allc)

(alla,allc,) = (set(s) for s in zip(*animaldictionary.keys())) ##### how else can you write this
##### how else can you rewrite the next code
print('\n'.join(['\t'.join((c,str(sum(animaldictionary.get(ac,0) for a in alla for ac in ((a,c,),))//12)))for c in sorted(allc)]))

print("="*60)
print("Month with the maximum number of visits for each station:")
print("Station             Month               Number")

print("1")
print("2")
4

1 に答える 1

3

あなたが示した2行は確かにかなり混乱しています。できる限りそれらを説明し、代替の実装を提案します。

alla最初のものはとの値を計算しますallc:

(alla,allc,) = (set(s) for s in zip(*animaldictionary.keys()))

これはallaallcリストを作成するために上ですでに実行したループとほぼ同じです。必要に応じて、完全にスキップできます。ただし、実際に理解できるように、それが何をしているのかを明らかにしましょう。

一番奥の部分はanimaldictionary.keys(). これは、辞書のすべてのキーを含む反復可能なオブジェクトを返します。のキーanimaldictionaryは 2 つの値のタプルなので、反復可能オブジェクトから得られるものです。keysほとんどの場合、ディクショナリを扱うときに実際に呼び出す必要はありません。キー ビューでの操作は通常、ディクショナリで同じ操作を直接実行するのと同じだからです。

zip次に進むと、キーはを使用した関数の呼び出しによってラップされますzip(*keys)。ここで 2 つのことが起こっています。まず、*構文は上記の iterable を個別の引数にアンパックします。したがって、animaldictionary のキーがこれらの 3 つのタプルを個別の引数として("a1", "c1), ("a2", "c2"), ("a3", "c3")呼び出した場合、これは呼び出されます。zipさて、何をするかzipというと、複数の iterable 引数を単一の iterable に変換し、それぞれから最初の値を持つタプルを生成し、次にそれぞれから 2 番目の値を持つタプルを生成します。zip(("a1", "c1"), ("a2", "c2"), ("a3", "c3"))そのため、ジェネレーター yielding とそれに続く が返され("a1", "a2", "a3")ます("c1", "c2", "c3")

次の部分は、式の各値をコンストラクターに渡すジェネレーター式zipですset。これは、重複を排除するのに役立ちます。setインスタンスは他の方法 (交差点の検索など) にも役立ちますが、ここでは必要ありません。

最後に、aとのc値の 2 つのセットが変数allaとに割り当てられますallc。それらは、すでに持っていたリストをそれらの名前 (および同じ内容!) に置き換えます。

これに代わる方法が既にあります。ここでは、計算allaallcてリストとして使用します。セットを使用すると多少効率が良くなる可能性がありますが、データ量が少ない場合はあまり問題にはなりません。それを行う別の、より明確な方法は次のとおりです。

alla = set()
allc = set()
for key in animaldict:  # note, iterating over a dict yields the keys!
    a, c = key  # unpack the tuple key
    alla.add(a)
    allc.add(c)

あなたが求めていた2行目は、平均化を行い、結果を巨大な文字列に結合して出力します。1 行に多くのことを詰め込むのは、本当に悪いプログラミング スタイルです。そして実際、それはそれをさらに混乱させるいくつかの不必要なことをします. 画面に一度に収まるように、いくつかの改行が追加されています。

print('\n'.join(['\t'.join((c,str(sum(animaldictionary.get(ac,0)
                                      for a in alla for ac in ((a,c,),))//12)
                           )) for c in sorted(allc)]))

これの最も内側の部分は ですfor ac in ((a,c,),)。これは 1 要素のタプルに対するループであるため、ばかげています。タプルの名前を に変更する方法です(a,c)ac、非常に紛らわしく、不要です。

acの 1 つの使用を明示的に書き出されたタプルに置き換えると、新しい最も内側のピースはanimaldictionary.get((a,c),0). これは特殊な書き方ですが、辞書にない場合にanimaldictionary[(a, c)]a が発生するリスクはありません。代わりに、存在しないキーに対して( に渡される) のデフォルト値が返されます。KeyError(a, c)0get

そのget呼び出しは次のようにまとめられています: (getcall for a in alla). これは、キーに指定された値を持つディクショナリからすべての値を取得するジェネレータ式ですc(値が存在しない場合のデフォルトはゼロです)。

次のステップは、前のジェネレータ式の値の平均を取ることです: sum(genexp)//12. //これは非常に簡単ですが、 for 除算を使用すると常に次の整数に切り捨てられることに注意してください。より正確な浮動小数点値が必要な場合は、単に/.

次の部分は、1 つのタプル'\t'.joinである引数を指定したへの呼び出しです。これは、または(c, avg)としてより明確に記述できる厄介な構造です。これらはすべて、値、タブ文字、および上記で計算された平均の文字列形式を含む文字列になります。c+"\t"+str(avg)"{}\t{}".format(c, avg)c

次のステップはリスト内包[joinedstr for c in sorted(allc)]表記です (ここで、joinedstr はjoin前のステップの呼び出しです)。ここでリスト内包表記を使用するのは少し奇妙です。なぜなら、リストは必要ないからです (ジェネレーター式でも同様です)。

最後に、リスト内包表記が改行で結合され、出力されます: print("\n".join(listcomp)). これは簡単です。

とにかく、この混乱全体は、いくつかの変数を使用してループ内で各行を個別に出力することにより、より明確な方法で書き直すことができます。

for c in sorted(allc):
    total_values = sum(animaldictionary.get((a,c),0) for a in alla)
    average = total_values // 12

    print("{}\t{}".format(c, average))

最後に、いくつかの一般的な提案があります。

まず、データ構造が、データの用途に最適ではない可能性があります。animaldictキーを持つディクショナリにするよりも(a,c)、各レベルに個別にインデックスを付ける入れ子構造にする方が理にかなっています。つまり、animaldict[a][c]. 逆の順序で索引付けされた同じ値を含む 2 番目の辞書を持つことも理にかなっている場合があります (たとえば、一方が索引付けされ[a][c]、別の辞書が索引付けされます[c][a])。このアプローチでは、繰り返しのためのallaandallcリストは必要ないかもしれません (メイン ディクショナリの内容を直接ループするだけです)。

2 つ目の提案は、コード スタイルに関するものです。変数の多くは、名前に意味がない (例: c) か、名前が間違った意味を暗示しているため、不適切な名前が付けられています。最も明白な問題は、実際にはキーの 2 つの部分 (AKAと) をアンパックする変数keyと変数です。他の状況では、キーと値を一緒に取得できますが、ディクショナリを直接ではなく、ディクショナリのビューを反復処理する場合のみです。valueacitems()

于 2012-11-14T02:26:23.057 に答える