2

私は現在、このプログラムで立ち往生しています。分子方程式 (Cs、Hs、および Os のみ) から化合物の分子量を決定しようとしています。また、[index +1] を正しくフォーマットする方法もわかりません。「x」の後の次の文字が数字なのか別の分子なのかを判断しようとしているからです。

デフメイン():

C1 = 0
H1 = 0
O1 = 0
num = 0

chemicalFormula = input("Enter the chemical formula, or enter key to quit: ")
while True:
    cformula = list(chemicalFormula)
    for index, x in enumerate(cformula):
        if x == 'C':
            if cformula[index + 1] == 'H' or cformula[index + 1] == 'O':
                C1 += 1
            else:
                for index, y in range(index + 1, 1000000000):
                    if cformula[index + 1] != 'H' or cformula[index + 1] != 'O':
                        num = int(y)
                        num = num*10 + int(cformula[index + 1])
                    else:
                        C1 += num
                        break

これは私が取得し続けるエラーです

Enter the chemical formula, or enter key to quit: C2
  File "/Users/ykasznik/Documents/ykasznikp7.py", line 46, in main
    for index, y in range(index + 1, 1000000000):
TypeError: 'int' object is not iterable
>>> 
4

6 に答える 6

2

この行を変更する必要があります

for index, y in range(index + 1, 1000000000):

for y in range(index + 1, 1000000000):
于 2013-05-24T05:15:49.373 に答える
1

これが問題を解決する方法に関する私の考えです。基本的に、現在の「状態」を追跡し、各文字を 1 回だけ反復処理するため、自分がどこにいるかなどを見失うことはありません。

def getWeightFromChemical(chemical):
    chemicals = {"C" : 6, "H" : 1, "O" : 8}
    return chemicals.get(chemical, 0)

def chemicalWeight(chemicalFormula):
    lastchemical = ""
    currentnumber = ""
    weight = 0

    for c in chemicalFormula:
        if str.isalpha(c): # prepare new chemical
            if len(lastchemical) > 0:
                weight += getWeightFromChemical(lastchemical)*int("1" if currentnumber == "" else currentnumber)
            lastchemical = c
            currentnumber = ""
        elif str.isdigit(c): # build up number for previous chemical
            currentnumber += c

    # one last check
    if len(lastchemical) > 0:
        weight += getWeightFromChemical(lastchemical)*int("1" if currentnumber == "" else currentnumber)

    return weight

ところで、これをリファクタリングして、そのコードを 2 回使わないようにする方法を知っている人はいますか? それは私を悩ませます。

于 2013-05-24T05:40:57.153 に答える
1

ここで提供される回答は、問題を解決するための 2 つの異なる側面に焦点を当てています。

  1. int is not iterable一部のコードを修正することによる、エラー ( ) に対する非常に具体的な解決策。
  2. コードの処理方法について、少し大きな視点。

1に関して、あなたの質問へのコメントは問題を指摘しました:あなたの内部ループでのタプルアンパックの構文。Tuple-unpacking の例は次のようになります。

a,b = ['a','b']

ここで、Python は右側 (RHS) の最初の要素を取り、それを左側 (LHS) の最初の名前に割り当て、RHS の 2 番目の要素を LHF の 2 番目の名前に割り当てます。

フォールトする内側のループ for index, y in range(index + 1, 1000000000)は、やろうとするのと同じです

index, y = 1

現在、整数は要素のコレクションではないため、これは機能しません。

2に関しては、モジュール化の戦略に焦点を当てる必要があります。これは基本的に、サブ問題ごとに関数を作成することを意味します。Python はほとんどこのために生まれました。(注: この戦略は、必ずしも各副問題に対して Python モジュールを作成することを意味するわけではありません。)

あなたの場合、主な目標はいくつかのサブ問題に分けることができます。

  1. 分子配列を取得します。
  2. シーケンスを個々のシーケンスに分割します。
  3. シーケンスを H、C、および O 要素に分割します。
  4. H、C、O 原子の数を指定して、分子量を計算します。

ステップ 3 と 4 は、独立した関数の優れた候補です。これらのコアの問題は、残りのコンテキストから分離されているからです。

ここでは、一度に 1 つのシーケンスしか取得できず、次の形式になると仮定します。

  • CH4
  • CHHHH
  • CP4H3OH

ステップ 3:

def GetAtoms(sequence):
  ''' 
  Counts the number of C's, H's and O's in sequence and returns a dictionary.
  Only works with a numeric suffices up to 9, e.g. C10H12 would not work.
  '''
  atoms = ['C','H','O']  # list of which atoms we want to count.
  res = {atom:0 for atom in atoms}
  last_c = None
  for c in sequence:
    if c in atoms:
      res[c] += 1
      last_c = c
    elif c.isdigit() and last_c is not None:
      res[last_c] += int(c) - 1
      last_c = None
    else:
      last_c = None
   return res

シーケンスの取得方法と分子量の計算方法に関係なく、この方法が (前提条件の下で) 機能することがわかります。後でアトム数を取得する方法の機能を拡張する必要がある場合は、残りのロジックに影響を与えることなくこれを変更できます。

ステップ 4:

def MolecularWeight(atoms):
  return atoms['H']*1 + atoms['C']*8 + atoms['O']*18

これで、全体のロジックは次のようになります。

while True:
  chemicalFormula = input("Enter the chemical formula, or enter key to quit: ")
  if len(chemicalFormula) == 0:
    break

  print 'Molecular weight of', chemicalFormula, 'is', MolecularWeight(GetAtoms(chemicalFormula))
于 2013-05-24T07:02:13.300 に答える
0

Range は、使用している Python のバージョンに応じて、int のリストまたは int の iterable を返します。その単一の int を 2 つの名前に割り当てようとすると、Python は自動化されたタプルのアンパックでその int を反復処理しようとします。

だから、変更

for index, y in range(index + 1, y):

for y in range(index + 1, y):

また、index + 1繰り返し使用しますが、ほとんどの場合、cformula で次のシンボルを検索します。それは外側のループの過程で変更されないため、一度独自の名前を割り当てて、その名前を使い続けます。

for index, x in enumerate(cformula):
    next_index = index + 1
    next_symbol = cformula[next_index]
    if x == 'C':
        if next_symbol == 'H' or next_symbol == 'O':
            C1 += 1
        else:
            for y in range(next_index, 1000000000):
                if next_symbol != 'H' or next_symbol != 'O':
                    num = y*10 + int(next_symbol)
                else:
                    C1 += num
                    break

また、コードをよりクリーンにするために、いくつかの定数をリファクタリングしました。書かれているように、内側のループはタプルの割り当てに失敗しており、y. また、内側のループを終了すると、インデックスが再びリセットされるため、すべての数字を繰り返し処理することになります。

現在のシンボルの後の部分文字列を反復処理する場合は、スライス表記を使用してそれらのすべての文字を取得できます。for subsequent in cformula[next_index:]

例えば:

>>> chemical = 'CH3OOCH3'
>>> chemical[2:]
'3OOCH3'
>>> for x in chemical[2:]:
...     print x
... 
3
O
O
C
H
3
于 2013-05-24T05:31:02.683 に答える