2

2の累乗を計算するコードを書き込もうとしていますが、キーとして10の累乗を持つ辞書に格納しているため、たとえば、2^9は次のように格納されます。

{0:2, 1:1, 2:5}

ここで、5 * 10 ^ 2 + 1 * 10 ^ 1 + 2 * 10^0があります。

だから現在、私は次のようなものを持っています

def foo():
    result={0:2}
    for i in range(2,10):
        for p in result.keys():
            result[p]*=2
        for p in result.keys():
            if result[p] / 10 != 0:
                result.setdefault(p+1,result[p]/10)
                result[p] = result[p] % 10

問題は

result.setdefault(p+1,result[p]/10)

にあったものはすべて上書きされresult[p+1]ます。辞書をチェックして、必要に応じて新しいキーを「初期化」することは可能ですが、その場でそれを行うためのよりエレガントな方法はありますか?結果を十分な長さに初期化することはできますが、「十分な長さ」であるかどうかは必ずしもわからないため、その場で延長する方が理にかなっているようです。

基本的に私はの線に沿って何かが欲しいです

for p in result.keys():
    if result[p] / 10 != 0:
        if result[p+1] exists:
            result[p+1]+=result[p]/10
        else:
            create result[p+1] and set its value to result[p]/10

どんな助けでも大歓迎です!

4

2 に答える 2

2

したがって、メインループで毎回行っていることは、各桁を 2 倍にしてから、余分な 10 を次の桁に繰り越すことです。問題は、最上位桁の次の桁が存在しないことです。

以下に説明する理由により、2 以外のべき乗では機能しませんが、これが解決策です。

def foo():
    result={0:2}
    for i in range(2,10):
        for p in result.keys():
            result[p]*=2
        for p in result.keys()[:]:
            if result[p] / 10 != 0:
                result[p+1] = result.get(p+1, 0) + result[p] / 10
                result[p] = result[p] % 10

元のコードから 2 つの重要な変更があります。

まず、現在のキーではなく、ループの前に辞書のキーのセットのコピーを反復処理するため[:]に、2 番目の の最後に追加する必要がありました。result.keys()その理由は、最後の桁が 5 より大きい場合、辞書に新しいキーを追加しようとしており、それを反復している間はそれを行うことが許可されていないためです。(理由は?

次に、元の質問があります。既存の値if p+1 in resultを保存するかr_p、追加するかを決定するためにチェックする必要がないようにするにはどうすればよいですか?r_p

カウントを扱うときは を使用しますcollection.Counter。これは に似ていdictますが、整数のみを格納し、欠落しているキーの値は 0 です。それ以外の場合は、通常は を使用しますcollection.defaultdictdictただし、デフォルト値を指定できる点が異なります。不足しているすべてのキーが持っていること。Counterまたはのいずれかを使用するdefaultdictと、必要なのは だけですresult[p+1] += result[p]/10

しかし、別のget方法dictを使用しました。デフォルト値を指定できる のメソッドです。理由は後で説明しますが、一般に、 に手を伸ばすとget、代わりにdefaultdictorが必要になる場合があることを覚えておいてください。Counter

これで、2 の累乗で実行され、機能します。しかし、2 つの理由から、他の累乗では機能しません。

まず、キャリーをランダムな順序で実行しています。2 の累乗の場合、運ぶことができるのは最大で 1 であり、1 が次の桁が上がるかどうかに影響を与える方法はありません。(8 はキャリーせず、8+1 もキャリーせず、現在は 9 を得る方法があります。) しかし、他のパワーの場合はそうではありません。

簡単なテストでは、これに気付かないかもしれません。(少なくとも CPython 2.7 と 3.2 では) 空のキーから始めて、dict少数の小さなキー (実際にはハッシュ値が小さいが小さいキーints はソートされた順序で自分自身にハッシュされ、何も削除されませんdict。多くの場合、順番に反復 (および出力) されます。しかし、一般に、順序は予測できず、信頼することはできません。

この問題の解決策はcollections.OrderedDict、追加された順序でキーを反復処理する を使用することです。defaultdictそして、それが私がor Counter:を使いたくなかった理由OrderedDictですget

次に、指数が 10 を超えると、100 を運ぶ必要がある場合があります。つまり、10 を運ぶ必要があり、0 であっても次の桁が桁上げされます。つまり、キーを単純にコピーすることはできません。前進。たとえば、75 の累乗を行っているとしましょう{0:5, 1:7}。各桁に 75 を掛けて{0:375, 1:525}. 今度は 37: を運びます{0:5, 1:562}。今度は 56: を運びます{0:5, 1:2, 2:56}。元のキーのコピーを繰り返し処理しただけなので、[0, 1]つまり、5 を保持する機会がありません。

その問題を解決するのはあなたに任せます。

ただし、古いディクショナリを変更するのではなく、新しいディクショナリを作成することを検討してください。その後、これらの問題をすべて回避できます。(原則として、状態を変更する代わりに純粋な関数を使用すると、多くの問題を回避できますが、もちろん、余分なコピーが必要になります。)

def double(d):
    result = Counter()
    for p in d:
        result[p] += d[p] % 10
        result[p+1] += d[p] / 10
    return result

digits={0:2}
for i in range(2,10):
    for p in digits:
        digits[p]*=2
    digits = double(digits)
于 2012-09-29T06:22:24.940 に答える
1

in次の構文を使用して、キーの存在を確認できます。

for p in result.keys()[:]:
    r_p = result[p] / 10

    if r_p != 0:
        if p + 1 in result:
            result[p + 1] += r_p
        else:
            result[p + 1] = r_p

Counterまたは、これを自動的に行うを使用できます。

from collections import Counter

result = Counter()

for p in result.keys()[:]:
    r_p = result[p] / 10

    if r_p != 0:
        result[p + 1] += r_p

また、あなたの状態は少し奇妙です。Python 2 またはPython 3result[p] / 10 == 0の場合のみ。result[p] < 10result[p] == 0

于 2012-09-29T04:22:47.630 に答える