Программное решение проблем в действии

Это вторая часть серии, посвященной программному решению проблем. Если вы не прочитали первый шаг по решению проблемы, вам следует прочитать его здесь. Вы также можете просмотреть мое репозиторий на github по этой теме, нажав здесь. В репо есть Jupyter Notebooks для обучения этой теме, а также видео, в котором я обучаю этому в живую.

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

If we list all the natural numbers below 10 that are  multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is  23. Find the sum of all the multiples of 3 or 5 below a given natural number.

Теперь у нас есть проблема, но вы можете подумать, что это слишком просто, ничего страшного. Это сделано для того, чтобы упростить демонстрацию, методы программного решения проблем работают также и со сложными проблемами.

Далее нам нужно напоминание о шагах:

1. Believe you can solve the problem
2. Read the problem for understanding
3. Start with a simple solution and scale up
4. Translate the process of step 3 into pseudocode
5. Translate the pseudocode into code
6. Debug and Refactor
7. Break It
8. Feedback and Practice

Да, и последнее: вам не нужно писать код до шага 5. Большая часть решения проблем, сложная часть программирования, может быть выполнена без кода. Решение проблем в программировании - это больше о том, как вы разбиваете проблему, чем о синтаксисе.

Шаг 1: верить

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

Шаг 2: прочтите проблему

Есть пара моментов, чтобы правильно прочитать проблему. Во-первых, просто объясните проблему себе, резиновой уточке или кому-то еще своими словами. Для нашей задачи мы можем записать это как:

Find all multiples of 3 or 5 below a given positive integer. Find the sum of these numbers.

Каков ожидаемый ввод? Что нам нужно дать нашему коду, чтобы все заработало? Мы хотим дать ему как можно больше подробностей, а не просто номер.

`n`, a natural number, positive integer. Looking at all numbers BELOW `n`

То же самое проделываем с выводом. Что такое «ответ», конечный продукт?

Positive integer (summing positive ints so no negative) representing the sum of multiples of 3 or 5. Minimum value is 0 (no multiples), max dependent on the size of `n`

Могу я разбить это на более мелкие проблемы? Если да, сделайте это и сначала решите их.

Find the Multiples of 3 below a given number - (i % 3 == 0)
Find the Multiples of 5 below a given number - (i % 5 == 0)
Add all those numbers - simple addition

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

Шаг 3. Начните с малого и масштабируйте

Начнем с простейшей возможной ситуации, что должно произойти?

n = 1
Answer = 0

Какой следующий самый маленький шаг мы можем сделать?

n = 2
Answer = 0

Продолжайте шагать, пока поведение не изменится.

n = 3
Answer = 0
n = 4
Answer = 3 #First number in our total is 3, which is a multiple of 3

Мы продолжаем шагать до 4, поскольку мы определили выше, что мы проверяем только числа ниже n. Теперь продолжайте шагать, пока не увидите все возможные случаи.

n = 5
Answer = 3
n = 6
Answer = 3+5 = 8 # A multiple of 5
...
# What about multiples of 3 and 5? Do we add that number twice?
n = 16
Answer = 3+5+6+9+10+12+15 = 60 # 15, a multiple of 3 and 5

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

Шаг 4. Запишите процесс, использованный на шаге 3.

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

Итак, какие шаги мы предприняли выше?

Start a running total at 0
Starting at 1, look at every integer below n
Check if it is a multiple of 3
Check if it is a multiple of 5
If it is a multiple of 3 or 5, add it to a running total
Once you have looked at all integers below n, total is your answer

Теперь упростите его и добавьте немного этой структуры программирования:

Set a total to 0
Look at numbers in range 1 to n
  Is the current number a multiple of 3 or 5?
  If so, add current number to total
Total is the answer

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

total = 0
for i in range 1 to n
  if (i % 3 is 0) or (i % 5 is 0)
    total = total + i
Answer = total

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

Шаг 5: псевдокод для кодирования

Если вы выполнили шаг 4 правильно, это должно быть довольно легко. Напишите работоспособный код на основе вашего псевдокода.

total = 0
for i in range(1, n):
  if i % 3 == 0 or i % 5 == 0:
    total = total + i
print(total)

Шаг 6. Отладка и рефакторинг

Часто у вас может быть решение, которое работает в вашей голове, но не работает при переводе. Убедитесь, что ваш код работает!

n = 10 # Added a declaration for `n`, now it should run
total = 0
for i in range(1, n):
  if i % 3 == 0 or i % 5 == 0:
    total = total + i
print(total)

Или, может быть, это действительно работает, но это код, который вам будет стыдно показать. Здесь вы исправляете это и делаете свой код СУХИМ. Ищите места, которые вы повторяете, или возможности сделать ваш код более универсальным, например, включить его в функцию.

# Make it reusable
def sum_of_multiples_3_5(n):
  total = 0

  for i in range(1, n):
    if ((i%3==0) | (i%5==0)):
      total+=i

  return total
sum_of_multiples_3_5(10)

Продолжайте эту очистку с пониманием списка и комментариями:

def sum_of_multiples_3_5(n):
  '''Return sum of all multiples of 3 or 5 below `n`'''
  return sum([i for i in range(1, n)
              if ((i%3==0) | (i%5==0))])
sum_of_multiples_3_5(10)

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

# Method with math instead of loops, refactored for efficiency
def sum_of_multi(target, multiple):
  #sum of all multiples up to and including target
  x = target // multiple
  return multiple*(x*(x+1))//2

def sum_of_multiples_3_5(target):
  #adjust target since the problem is non-inclusive
  target = target-1
  return (sum_of_multi(target, 3) +
          sum_of_multi(target, 5) -
          sum_of_multi(target, 15))
sum_of_multiples_3_5(3)

На решение, приведенное выше, намекают, если мы переформулируем нашу проблему (шаг 2) как:

Sum the multiples of 3 below n, repeat for multiples of 5, remove overlapping values and add summations together.

Шаг 7: сломайте это

Ждать! Какие?! Зачем мне его ломать? Все просто, люди и компьютеры тупые, кто-то сломает это, так что с таким же успехом это можете быть вы. Итак, как нам взломать код? Мы ищем крайние случаи, крайние случаи и даже то, что не должен делать здравомыслящий человек.

# Some ways that might break our code
1. Non-natural numbers
2. Really big numbers
3. Really small numbers
4. Wrong Data type, string instead of number
5. No value for `n`
6. Extra parameter values

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

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

8. Обратная связь и практика

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

Попросите мнение и критику, как это могло быть написано лучше? Слишком стеснительный или никого вокруг, самокритика и вопросы в Интернете - погуглите свою проблему и посмотрите, как это сделали другие люди.

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

Конец - пока ...

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