Как суммировать целые числа в цикле while в диапазоне

#python #loops

#питон #петли

Вопрос:

ребята!

Я пытаюсь выполнить оценочное задание. Это требует от меня ввода количества ветвей для определенных предметов (химия, компьютеры, биология, физика, искусство). Затем он просит меня указать количество книг по этим предметам в каждой ветке. Затем он просит меня вычислить общее количество книг и вычислить среднее значение. Я почти закончил с этим, но для меня есть одно последнее препятствие — как вычислить сумму книг в этих отраслях и предметах. Я был бы очень признателен, если бы вы объяснили мне это.

Вот этот код:

 #!/usr/bin/env python3

branches = 0
while branches < 1:
  try:
    branches = int(input("Enter branches: "))
  except (ValueError, TypeError):
    print("Number of branches must be an integer")
  else:
    if branches < 1:
      print("Number of branches must be at least 1")



for i in range(branches):
  for category in ["Computer", "Physics", "Chemistry", "Biology", "Arts"]:
    books = -1
    while books < 0:
      try:
        string_branches = str(i 1)
        books = int(input("Enter the number of books for "   category    " of branch "   string_branches   " :" ))
      except (ValueError, TypeError):
        print("Number of books must be an integer")
      else:
        if books < 0:
          print("Number of books must be at least 1")
        books_total = 0
        books_total = books   books 
books_per_category = books_total  / branches
print("Following the information of all the branches of the main library: ")
print("Total number of books: ",books_total )
print("Average numbers of books per category: ",  books_per_category)
 

Вопрос на миллион долларов заключается в следующем: как сделать так, чтобы книги складывались в общую сумму? Поверьте мне, я перепробовал кучу разных методов, но, похоже, они не работают.

Возможно, я не определил функцию чего-либо.

Ответ №1:

Я хотел дать вам более подробный ответ о CLI, о том, как вы могли бы очистить код, разделив его на функции, как вы могли бы определить свои собственные исключения и как вы могли бы удалить один из двух ваших основных циклов. Более того, вместо того, чтобы суммировать число по ходу дела, я решил сохранить все входные данные. Например, результатом может быть:

 {'Computer': [1, 3], # 2 branches with 1 and 3 books
'Physics': [4], # 1 branch with 4 books
 'Chemistry': [2, 3, 2],
 'Biology': [2],
 'Arts': [2]}
 

Код разделен на 3 части:

  1. Исключения
  2. Входные данные
  3. Основной цикл

Вы можете определить свое собственное исключение. Вы можете прочитать, например, эту статью. Более того, я решил ограничить количество возможных попыток для пользовательского ввода до 5. Таким образом, программа всегда имеет конец. Я определил RETRIES заглавными буквами, что обычно я рассматриваю это как импортированную глобальную переменную.

 #%% Define custom exceptions
RETRIES = 5

class ConsecutiveWrongAnswers(Exception):
    """Exception raised when the users input too many times a wrong answer
    to a query. 

    Attributes:
        retries -- Number of retries
    """

    def __init__(self, retries):
        self.retries = retries
        self.message = f'The input was invalid more than {self.retries} times!'
        super().__init__(self.message)
        
class InvalidBranchNumber(Exception):
    """Exception raised for errors in the branch number input.

    Attributes:
        branch -- invalid branch number.
        message -- explanation of the error.
    """

    def __init__(self, branch, 
                 message="Branch number input should be a positive integer."):
        self.branch = branch
        self.message = message
        super().__init__(self.message)

    def __str__(self):
        return f'{self.branch} -> {self.message}'
    
class InvalidBooksNumber(Exception):
    """Exception raised for errors in the branch number input.

    Attributes:
        books -- invalid books number.
        message -- explanation of the error.
    """

    def __init__(self, branch, 
                 message="Books number input should be a positive integer."):
        self.books = books
        self.message = message
        super().__init__(self.message)

    def __str__(self):
        return f'{self.books} -> {self.message}'
 

Затем я определяю функции ввода, которые позволят пользователю пытаться ввести допустимый ввод до RETRIES нескольких раз. Входные данные проверяются перед их возвратом.

 #%% Input functions
def input_branch_number(category, retries=RETRIES):
    
    def check_branch(branch):
        if branch <= 0:
            raise InvalidBranchnNumber(branch)
    
    attempt = 0
    while True:
        attempt  = 1
        if attempt > retries:
            raise ConsecutiveWrongAnswers(retries)
        
        try:
            branch = int(input(f'[IN] Branch number for category {category}: '))
            check_branch(branch)
            break
        except (InvalidBranchNumber, ValueError, TypeError):
            print (f"Invalid ID: branch number should be a positive integer.)")
        except:
            raise
    
    return branch

def input_books_number(category, branch_id, retries=RETRIES):
    
    def check_books(books):
        if books <= 0:
            raise InvalidBooksNumber(books)
    
    attempt = 0
    while True:
        attempt  = 1
        if attempt > retries:
            raise ConsecutiveWrongAnswers(retries)
        
        try:
            books = int(input(f'[IN] Books number for (category, branch n°) - ({category}, {branch_id}): '))
            check_books(books)
            break
        except (InvalidBooksNumber, ValueError, TypeError):
            print (f"Invalid ID: branch number should be a positive integer.)")
        except:
            raise
    
    return books
 

И, наконец, основной цикл теперь намного проще для чтения:

 #%% Main loop

# Initialize the data structure which will contain the number of books per category and per branch. 
books_logs = dict()

for category in ["Computer", "Physics", "Chemistry", "Biology", "Arts"]:
    # Input the number of branch per category
    branch = input_branch_number(category)
    
    # For each category, initialize an empty list. The list will be filled by the number of books per branch
    books_logs[category] = list()
    for branch_id in range(branch):
        # Input the books for each (category, branch_id)
        books = input_books_number(category, branch_id)
        books_logs[category].append(books)
 

Теперь вы можете работать со books_logs словарем, чтобы суммировать по ветвям, по категориям или получить итоговое значение.

N.B: Для форматирования строк вместо суммирования объектов str, как вы это делали, я предлагаю вам использовать флаг форматирования python, который улучшает читаемость:

 f'This is a formatting string with {n_characters} characters and {n_words}.'
 

Промежуточный элемент {} может быть любым, он будет вычислен / выполнен python. У вас могут быть формулы, например

 k = 2
f'I want to format with leading zeros integer {k} to get {str(k).zfill(3)}'
 

Наконец, я выбрал очень простую структуру данных, но вы можете заменить словарь другим. В частности, как предложил Рутгер Рихарт, вы могли бы использовать фрейм данных pandas.

Комментарии:

1. Матье, я действительно ценю вашу помощь! Мне очень жаль, но я забыл упомянуть, что я новичок в python, и я едва понял основные понятия циклов и итераций XD Эта задача слишком стареет, и мне пришлось просить своих одноклассников и учителей о итерациях XD

2. @HeorhiyKremlov Я мог бы об этом догадаться. Вот почему, поскольку ваш код также был хорошо написан с учетом неправильного ввода пользователем, я хотел дать вам немного больше возможностей. Постарайтесь как можно скорее освоить хорошую практику. Простой способ, который действительно улучшает фрагмент кода, — это разделить код на основные блоки, функции, что я и сделал здесь с 3 частью (4, если мы включаем функции проверки, которые в данном случае я включил в качестве подфункций ввода).

3. Поддержал этот ответ за подробное объяснение.

Ответ №2:

Что вы сделали неправильно, так это то, что вы присваиваете 0 books_total для каждой итерации в категории. Вам нужно будет объявить его перед чтением входных данных и добавлять к нему входные данные на каждой итерации.

 books_total = 0 # init here
for i in range(branches):
  for category in ["Computer", "Physics", "Chemistry", "Biology", "Arts"]:
    books = -1
    while books < 0:
      try:
        string_branches = str(i 1)
        books = int(input("Enter the number of books for "   category    " of branch "   string_branches   " :" ))
      except (ValueError, TypeError):
        print("Number of books must be an integer")
      else:
        if books < 0:
          print("Number of books must be at least 1")
    books_total  = books # add the input to books_total
 

Комментарии:

1. Потрясающе, спасибо, сэр! Работает так, как должно! Это добавляет книги — я не могу себе представить, что я потратил 6 часов, пытаясь решить эту проблему -_-

Ответ №3:

Во-первых, это утверждение удваивает ваше количество книг, что делает его неправильным вычислением

 books_total = books   books 
 

вы можете сделать:

 books_total  = books 
 

и вам нужно объявлять total_books вне цикла, и каждый раз, когда вы вводите новую книгу, вы добавляете это число к общему количеству книг.

Комментарии:

1. Файзан, спасибо! Теперь я вижу, как работает код. Я потратил так много времени на попытки решить эту проблему -_-

Ответ №4:

Возможно, вы захотите поместить свои данные в фрейм данных Pandas.

 #!/usr/bin/env python3

import pandas as pd

branches = 0
while branches < 1:
  try:
    branches = int(input("Enter branches: "))
  except (ValueError, TypeError):
    print("Number of branches must be an integer")
  else:
    if branches < 1:
      print("Number of branches must be at least 1")


df = pd.DataFrame({})

for i in range(branches):
  for category in ["Computer", "Physics", "Chemistry", "Biology", "Arts"]:  
    books = -1
    while books < 0:
      try:
        string_branches = str(i 1)
        books = int(input("Enter the number of books for "   category    " of branch "   string_branches   " :" ))
        df[category string_branches] = pd.Series(books)

      except (ValueError, TypeError):
        print("Number of books must be an integer")
      else:
        if books < 0:
          print("Number of books must be at least 1")
        books_total = 0
        books_total = books   books 
books_per_category = books_total  / branches
print("Following the information of all the branches of the main library: ")
print("Total number of books: ",books_total )
print("Average numbers of books per category: ",  books_per_category)
 

Оттуда вы могли sum бы легче выполнять различные операции.

 df.apply(sum, axis=1)
 

Или просуммируйте его, например, по категориям.

 df['Computer1'] df['Computer2']
 

Если у вас много ветвей, просто используйте строку («Компьютер») для вычисления суммы по ветвям:

 df.loc[:, list(df.columns[df.columns.str.contains(pat = 'Computer')])].apply(sum, axis=1)
 

Комментарии:

1. Рутгер, спасибо за ваш ответ, сэр! Я действительно ценю вашу помощь 🙂 Но я только начал изучать Python и только начал понимать базовые функции, такие как while , for in и if .

2. @HeorhiyKremlov: Это не проблема, каждый разработчик начинал в какой-то момент с нуля. Приятного путешествия :-).