2013-05-24 4 views
2

В настоящее время я застрял в этой программе. Я пытаюсь определить молекулярную массу соединения с учетом молекулярного уравнения (только Cs, Hs и Os). Я также не уверен, как правильно форматировать [index +1], поскольку я пытаюсь определить, что следующий символ после «х» должен увидеть, является ли это числом или другой молекулой.Итерация и индексация

def main():

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 
>>> 
+0

Какова цель внутреннего цикла? –

+0

Где именно вы намерены получить 'y' из во внутреннем цикле, не ясно - это, конечно, не из' range() '. Устранение этого вопроса позволило бы дать более окончательный ответ. – kampu

+0

ТипError, который вы получаете, заключается в том, что Python пытается выполнить итерацию через один int, чтобы присвоить значения двум именам. Это было названо «распаковкой кортежа» и является частью того, почему «a», «b», «a» является действительным Python для замены имен. – pcurry

ответ

2

Вы должны изменить эту строку

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

в

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

Возможно, вам захотелось сказать: «Ты * должен * изменить ...». – Bakuriu

+0

@Bakuriu спасибо, исправлено. – Roger

0

Изменить

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

в

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

Хотя вы можете рассмотреть переименование внешнего контура или внутренний контура index для ясности

0

возвращается Диапазон либо списка междунар, или итерабельность int, в зависимости от используемой версии Python. Попытка назначить этот единственный int на два имени заставляет 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 
+0

Спасибо, ваш ответ был очень полезным. Я ценю, что вы очищаете мой код. Не могли бы вы немного рассказать об итерации над подстрокой? Похоже на то, что мне нужно, хаха, но, честно говоря, я очень новичок в Python, поэтому я не совсем понимаю, что это значит. –

+0

Я расширил свой ответ на примере использования среза, чтобы получить подстроку строки, через которую вы повторяются. – pcurry

0
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): 

Это действительно плохая идея. Вы переписываете значение индекса из внешнего цикла со значением индекса из внутреннего цикла. Вы должны использовать другое имя, например index2 для внутреннего цикла.

Кроме того, когда вы говорите for index, y in range(index + 1, 1000000000):, вы действуете так, как будто вы ожидаете range(), чтобы создать последовательность из 2-х кортежей. Но range всегда производит последовательность int s.

Роджер предложил for y in range(index + 1, 1000000000):, но я думаю, что вы намерены получить значение y откуда-то еще (это не понятно куда. Может быть, вы хотите использовать второй аргумент enumerate() указать значение, чтобы начать с, а?

То есть, для index2, у в Перечислим (whereeveryoumeanttogetyfrom, индекс + 1)

так, что index2 равен индексу +1 на первом шаге через петлю, индекс +2, на втором и т.д.

1

Вот мой идентификатор ea о том, как решить проблему. В основном, вы отслеживаете текущее «состояние» и повторяете каждый символ ровно один раз, поэтому вы не можете потерять информацию о том, где вы находитесь или что-то в этом роде.

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 

Кстати, может ли кто-нибудь увидеть, как реорганизовать это, чтобы не иметь этот кусок кода дважды? Меня это беспокоит.

1

Ответы, здесь сосредоточены на двух различных аспектах решения вашей проблемы:

  1. очень конкретное решение для вашей ошибки (int is not iterable), путем исправления код.
  2. Немного больше о том, как обращаться с кодом.

Что касается , комментарий к вашему вопросу отметил вопрос: синтаксис кортежа-распаковка во внутреннем цикле. Пример кортежа распаковке бы

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

Здесь, Python бы первый элемент правой стороны (РИТ) и присвоить его имя на левой стороне (LHS), вторая элемент RHS и присвоить его второму имени в LHF.

Ваш внутренний цикл, разломы, for index, y in range(index + 1, 1000000000), эквивалентно пытаться сделать

index, y = 1 

Теперь целое не является совокупность элементов, так что это не будет работать.

Что касается , вы должны сосредоточиться на стратегии модульности, который в основном означает, что вы пишете функцию для каждого суб-проблемы. Для этого был почти рожден Питон. (. Обратите внимание, что эта стратегия не обязательно означает, что написание 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)) 
+0

О, вау, ты спасатель. Я попытаюсь использовать этот ответ, чтобы помочь мне решить проблему. Я не собираюсь звучать вперед/идти против этикета, но если я просто скопирую/вставлю все эти отдельные части под одной главной в моем окне, будет ли это работать как функция? еще раз, действительно новый на python и выход из моей лиги прямо сейчас –

+0

Это крутая часть; если у вас есть 'main'-function, то эти два определения метода не должны быть * внутри * основной функции, но могут быть определены до или после нее! Это только последний кодовый блок ('while True: ...'), который будет в вашей 'main'-функции. – MrGumble

+0

хорошо, поэтому я просто попытался собрать все это вместе, и мне все еще нужны первые шаги хаха ... любые предложения по направлениям для первых двух? –