Питон суммы кратных некоторых чисел в диапазоне


Я видел задачи проект Эйлера онлайн и я решил написать несколько. В первой задачи требовалось найти сумму кратных. Поэтому я решил, что мой код будет в состоянии найти сумму кратных для любого заданного диапазона, и для любого количества натуральных чисел.

Мой код позволяет пользователю вводить столько натуральных чисел так, как они хотят, а затем задать диапазон мультипликаторов, что пользователь хочет получить сумму, а потом сумма этих кратных.

Я просто хотел любой вход, если есть более эффективный способ сделать это.

def main():
    # Initialize variables
    multiples = []
    sums = []
    i = 0
    integers = 1

    # Detemines the number of multiples from user
    while True:
        try:
            num_mul = int ( input ( 'How many multiples are you using in total?: ' ) )
            break
        except ValueError as e:
            print ( e )

    # Takes multples and store in list
    while True:
        try:
            for y in range ( num_mul ):
                multiples.append ( int ( input ( 'Please input your No.{} integer here: '.format(integers) ) ) )
                integers = integers + 1
            break
        except ValueError as e:
            print ( 'Integer Values ONLY' , e )

    # determine the start and stop of the range from user
    while True:
        try:
            start = int ( input ( 'Start of range: ' ) )
            stop = int ( input ( 'End of range: ' ) ) + 1
            break
        except ValueError as e:
            print ( e )

    # Figures out the multiples of the numbers given between the start and end range
    while i < len ( multiples ):

        for k in range (start, stop ):
            if (k % multiples[i]) == 0:
                sums.append(k)
            else:
                continue

        i = i + 1  # increments through the list values by 1

    x = sum(set(sums))  # Gets rid of duplicated values and sums the list of values

    print ( 'Your SUM total is {}.'.format ( x ) )


if __name__ == "__main__": main ( )


Комментарии
2 ответа

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

Будет объяснить вам какие-то шаги :)

Чтение входных данных

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

def read_integer(input_message):
while True:
try:
number = int(input(input_message))
return number
except ValueError:
print('Integer Values ONLY')

Вы просто передать сообщение, которое вы хотите, чтобы появиться на экране и она будет игнорировать все, отличное от целого значения, раз задаете вопрос

Повторное использование переменных

Иногда, вы можете использовать ту же переменную для разных целей.

Для того, чтобы считать ввод в петлю, вы можете использовать ту же переменную, которая представлена в курсе в качестве индекса, во избежание создания новой переменной integers только для этого

Так этот код

integers = 1
for y in range ( num_mul ):
multiples.append ( int ( input ( 'Please input your No.{} integer here: '.format(integers) ) ) )
integers = integers + 1

Может быть уменьшена до

for y in range ( num_mul ):
multiples.append ( int ( input ( 'Please input your No.{} integer here: '.format(y+1) ) ) )

Избежать ненужного кода

В конце концов, есть else условии, что просто продолжается на следующей итерации. Что произойдет, даже если else условие не существует, сэкономив вам несколько лишних строк кода

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

if (k % multiples[i]) == 0 and k not in sums:
sums.append(k)

Именования

Вы могли бы использовать немного лучше, именования переменных, и таким образом, я изменил немного некоторые из них, так что вы можете проверить, но такие вещи, как num_mul могут быть лучше поняты при более длительном именования, как multiples_count

Резюме

Вы можете проверить, как ваше решение будет выглядеть с этой функции, я применил изменения, которые я предложил вам:

def read_integer(input_message):
while True:
try:
number = int(input(input_message))
return number
except ValueError:
print('Integer Values ONLY')

def main():
# Initialize variables
multiples = []
sums = []

# Determines the number of multiples from user
input_message = 'How many multiples are you using in total?: '
multiples_count = read_integer(input_message)

# Takes multiples and store in list
for y in range(multiples_count):
input_message = 'Please input your No.{} integer here: '.format(y+1)
new_multiple = read_integer(input_message)

multiples.append(new_multiple)

# determine the start and stop of the range from user
input_message = 'Start of range: '
start = read_integer(input_message)

input_message = 'End of range: '
stop = read_integer(input_message)

# Figures out the multiples of the numbers given between the start and end range
for i in range(multiples_count):
for k in range(start, stop):
if (k % multiples[i]) == 0 and k not in sums:
sums.append(k)

x = sum(sums) # Gets rid of duplicated values and sums the list of values

print('Your SUM total is {}.'.format(x))

if __name__ == "__main__":
main()

7
ответ дан 4 марта 2018 в 01:03 Источник Поделиться

Более красивые петли

Начиная с этот кусок кода, мы начнем идти на более элегантный реализации:

i = 0
...
while i < len ( multiples ):

for k in range (start, stop ):
if (k % multiples[i]) == 0:
sums.append(k)
else:
continue

i = i + 1 # increments through the list values by 1

Мы могли бы начать сбривать ООН-необходимы: пустые строки и else-continue.

Мы можем также принести i = 0 часть ближе к блоку на самом деле использовать его.

Кроме того, комментарий # increments through the list values by 1 не приносит много информации. В любое время вы добавить комментарий, вы можете спросить себя: "Может ли это реально помочь кто-нибудь читал код ?". Общее правило большого пальца заключается в том, чтобы задокументировать "зачем" нежели "как": скажите, что вы хотите/нужно сделать и почему, а не как вы это делаете.

Наконец, i = i + 1 может быть написано i += 1.

На этом этапе, мы имеем:

i = 0
while i < len ( multiples ):
for k in range (start, stop ):
if (k % multiples[i]) == 0:
sums.append(k)
i += 1

Потом, все еще может быть улучшена. Для начала, вы называете len функции на каждой итерации. Это не очень дорогая операция, но это все равно ненужный. Однако, фактической частью, чтобы изменить это, чтобы переключить while петля для for петли: ваша ситуация выглядит как типичная ситуация для использования for петли. С помощью range функции вы уже знаете:

for i in range(len(multiples)):
for k in range (start, stop ):
if (k % multiples[i]) == 0:
sums.append(k)

Обратите внимание, что это не нужно инициализировать i, чтобы увеличить его после каждой итерации, и len функция вызывается только один раз. Это выглядит как идеальное решение, не так ли ?

Не совсем! Этот цикл использует индекс, чтобы пройти через элементы контейнера. Это, как большинство людей (привыкли) делаете в различных языках программирования. Однако на Python определяет объекты, которые Iterable и чистого синтаксиса, чтобы использовать их. Вы можете просто написать for num in multiples. Это очень хорошо объяснил Нэд Батчелдер говорить "петли, как родной"

for mul in multiples:
for k in range(start, stop):
if (k % mul) == 0:
sums.append(k)

Кроме того, это может быть написано с помощью списка понимания, но я предпочел бы не делать вещи слишком сложно сейчас.

Обработка повторяющихся значений

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

Комментарий Graipher предложил с помощью набора напрямую. Это очень хорошее решение. Вы бы что-то вроде:

sums = set()
for mul in multiples:
for k in range(start, stop):
if (k % mul) == 0:
sums.add(k)

Не сильно меняется :-)

Ради обучения новых вещей, мы могли бы пойти на другой подход. Что делать, если лучший способ справиться с дубликатами не иметь дубликатов в первую очередь. На данный момент, ваш код перебирать range(start, stop) много раз. Изменение кода немного, мы могли бы перебрать его только один раз.

sums = []
for k in range(start, stop):
# TODO: if a number in multiples divides k
sums.append(k)

Это может быть:

sums = []
for k in range(start, stop):
for mul in multiples:
if k % mul == 0:
sums.append(k)
break

Что делает ваш код для тестирования

Задачи проекта Эйлера дает вам пример входных и ожидаемых выходных данных. Вы могли бы использовать этот шанс, чтобы писать тесты, чтобы гарантировать, что ваш код является действительным в отношении этого примера. Кроме того, это приведет к написанию небольших, легче использовать и понять функции. Мы можем представить себе, писать что-то вроде: def sum_of_multiples(limit, multiples) и убедившись, что sum_of_multiples(10, [3, 5]) == 23.

Математическая оптимизация

Это действительно не имеет значения на эту проблему, но чем дальше вы идете в проблемы проекта Эйлера, тем меньше он будет о написании прямой брутфорс решение, и чем больше становится о поиске математические свойства уметь писать эффективные решения.

По этой проблеме, там уже гораздо больше удовлетворения, решение математики. Ключевым моментом является то, что у нас есть формулы для вычисления количество количество из i для j. Это может легко использоваться, чтобы вычислить сумму кратных 3 или 5 между i и j. Затем, это приводит к число которого вы ищете (Примечание: кратные 15 учитывается два раза, но вы можете еще раз вычислить их сумму легко).

4
ответ дан 4 марта 2018 в 10:03 Источник Поделиться