Всем привет. Я ни в коем случае не эксперт по программированию, javascript или Free Code Camp, но я подумал, что другим новичкам может быть интересно посмотреть, как один человек решает алгоритмические упражнения.

Я на 100% уверен, что есть более эффективные и элегантные решения, чем то, что я представляю здесь. Я просто хочу представить свой мыслительный процесс, когда я работаю над упражнением. По моему опыту, гораздо сложнее найти объяснение того, как люди достигают решений проблем программирования, чем найти решения проблем программирования.

Я выбираю упражнение Суммировать все нечетные числа Фибоначчи. Вот описание дословно:

Учитывая положительное целое число, вернуть сумму всех нечетных чисел Фибоначчи, которые меньше или равны num.

Первые два числа в последовательности Фибоначчи — это 1 и 1. Каждое дополнительное число в последовательности является суммой двух предыдущих чисел. Первые шесть чисел последовательности Фибоначчи — это 1, 1, 2, 3, 5 и 8.

Например, sumFibs(10) должно возвращать 10, поскольку все нечетные числа Фибоначчи меньше 10 равны 1, 1, 3 и 5.

И вот тесты, которые должно пройти решение:

sumFibs(1) должен возвращать число.

sumFibs(1000) должен вернуть 1785.

sumFibs(4000000) должен вернуть 4613732.

sumFibs(4) должно вернуть 5.

sumFibs(75024) должен вернуть 60696.

sumFibs(75025) должен вернуть 135721.

До планирования

Сначала я убеждаюсь, что понял упражнение. Что такое ввод? Каков ожидаемый результат? По-моему, что мне нужно сделать, чтобы получить результат из ввода?

Давайте ответим на эти 3 вопроса:

1) Что такое ввод?

Любое положительное целое число.

2) Каков ожидаемый результат?

Сумма всех чисел Фибоначчи, меньших или равных входным данным.

3) Что мне нужно сделать, чтобы получить вывод из ввода?

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

В ПОРЯДКЕ. Я вижу, что это упражнение разбивается на два шага. Я уже могу начать представлять в своей голове, что я хочу сделать. Вероятно, я могу использовать цикл for для создания списка чисел Фибоначчи. Когда у меня есть этот список, я могу действительно легко выполнить некоторую обработку этого списка, чтобы избавиться от четных чисел и просуммировать оставшиеся числа.

Давайте пройдемся по каждому шагу.

Цикл For

Числа Фибоначчи генерируются следующим образом: начиная с 0 и 1 в качестве первых чисел, следующее число представляет собой сумму двух предыдущих чисел. 0+1 = 1, 1+1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8 и так далее.

Я могу себе представить самый простой и очевидный способ сделать это — использовать две целочисленные переменные (a, b) и массив (fibList). a и b начнут жизнь как первые два числа Фибоначчи 0, 1. fibList содержит первые два числа Фибоначчи [0, 1].

Каждый раз при обходе цикла мы будем добавлять сумму a и b в конец fibList. Затем мы сдвигаем a и b вперед к двум последним значениям в fibList.

Для этого первого тестового цикла давайте полностью проигнорируем ввод sumFibs() и просто используем итератор для запуска цикла 10 раз:

Это дает нам следующий результат:

Прохладный! Оно работает. Его генерация чисел Фибоначчи.

Честно говоря, я не написал это идеально за один раз. Я все еще новичок, и мне пришлось исправить несколько ошибок даже в этой простой программе. Моя первая попытка дала мне список степеней двойки, потому что я случайно установил a = a+b. Мне также пришлось попробовать несколько разных способов добавления в fibList и переназначения a и b.

pop(-1) казался самым простым способом, но он действует разрушительно на исходный список, так что это не сработало. slice(-1) тоже сработал бы, но он возвращает список, а не одно целое число (что мне нужно для a и b). slice(-1)[0] будет работать, но мне показалось, что это выглядит забавно. Я остановился на fibList[fibList.length-1]. Это выглядело немного более понятным для меня, но, насколько я знаю, нет никакой разницы.

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

Это выглядело хорошо, но работало не так, как хотелось бы:

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

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

На данный момент я больше не использую итератор «i» и могу удалить его. Давайте также заменим мой жестко заданный лимит параметром sumFibs() num:

Теперь я могу ввести любое значение в sumFibs() и получить список чисел Фибоначчи, идущих до этого значения (и, вероятно, за ним на одно значение).

Давайте двигаться дальше и начать обработку списка.

Обработка списка

Я собираюсь попробовать использовать некоторые методы функционального программирования, которые я изучил в разделе «Объектно-ориентированное и функциональное программирование» курса FCC по интерфейсу.

Первое, что мне нужно сделать, это избавиться от этого лишнего числа Фибоначчи, которое я получаю всякий раз, когда num > 3. Похоже, это отличное место для использования filter():

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

Это звучит очень похоже на map(). Я считаю, что разница в том, что filter() используется только с true или false условными операторами, где исходное значение передается, если функция возвращает true. Map(), с другой стороны, вставит фактический результат функции в новый массив.

Ради интереса мы можем проверить это, заменив filter() на map(). Я ожидаю, что на выходе будет список значений true и false на основе условного el ‹= num:

Как видите, вывод представляет собой массив значений true и false.

Мы использовали filter(), чтобы убедиться, что наш список находится в правильном диапазоне. Давайте воспользуемся им еще раз, чтобы избавиться от надоедливых четных чисел:

Здесь я использую по модулю (%) 2 для проверки остатков при делении каждого значения на 2. Функция возвращает true, если остаток НЕ равен нулю. Затем фильтр передает в новый массив только нечетные числа.

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

Подобно map() и filter(), функция и массив передаются в reduce() в качестве параметров. Функция получает ряд параметров, связанных со значениями в массиве, начиная с начала массива. Функция берет из массива значения, равные количеству его параметров, и обрабатывает их. Затем выходные данные функции повторно вводятся в функцию в качестве ее первого параметра вместе со следующими значениями из исходного массива, и процесс продолжается до тех пор, пока он не обработает все значения в исходном массиве и не обработает их все вместе. в окончательный вывод.

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

Теперь мы получаем на выходе одно значение, равное сумме всех элементов массива.

Давайте запустим тесты по-настоящему и посмотрим, что произойдет:

Миссия выполнена!!

Возможно, это не самая красивая программа, но она помогает, и я многому научился в процессе. Это в значительной степени рабочий процесс, который я использовал для всех упражнений FCC, которые я делал. Обычно я не описываю все так подробно, но я следую этому основному распорядку. Сначала я излагаю (обычно в уме), о чем меня просит упражнение, затем я разбиваю его на части, над которыми я могу работать независимо, и, наконец, я начинаю писать код для каждой из этих частей, убедившись, что они работают сами по себе, прежде чем я ожидать, что полная программа пройдет все финальные тесты.

Теперь мне интересно, смогу ли я избавиться от цикла for и написать всю программу более функциональным способом. Какие-либо предложения?