Как в Elm получить каждый четный индекс в списке и вернуться в виде другого списка?

elm
1
WP0987 27 Ноя 2016 в 09:38

2 ответа

Лучший ответ

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

Вот как вы могли бы это сделать, написав свою собственную функцию. Мы напишем вспомогательную функцию everySecond_, которая выглядит так.

everySecond_ : List a -> Int -> List a
everySecond_ list index =
    case list of
        [] ->
            []

        hd :: tl ->
            if index % 2 == 0 then
                hd :: (everySecond_ tl (index + 1))
            else
                everySecond_ tl (index + 1)

Эта функция принимает список и число, обозначающее индекс текущего заголовка этого списка. Нам нужно передать это как аргумент функции.

Затем мы проводим сопоставление с образцом в списке. Если он пуст, мы возвращаем пустой список; это сигнализирует об окончании рекурсии. Последний элемент в списке - всегда пустой список. Если это не пустой список, мы берем голову (первый элемент) и хвост (список, представляющий все последующие).

Если наш аргумент index был четным (% 2 == 0 означает «при делении на два, не оставляет остатков»), мы хотим сохранить этот элемент, поэтому добавляем его в начало списка, который мы создаем. вверх и продолжаем построение, снова вызывая everySecond_ с хвостом нашего текущего списка и увеличенным номером индекса.

Если он не четный, мы не хотим сохранять этот элемент, поэтому просто возвращаем everySecond_ tl (index + 1), следующий этап списка, и процесс повторяется.

В этом вся логика. Но это означает, что нам нужно будет вызвать everySecond_ [foo, bar, baz] 1, чтобы использовать нашу функцию, всегда передавая 1 в качестве аргумента по умолчанию. Это не интуитивно. И поэтому мы назвали его everySecond_ с подчеркиванием - это не то, что мы собираемся вызывать у людей, это вспомогательная функция, которая будет существовать за кулисами. Мы можем скрыть это за

everySecond : List a -> List a
everySecond list =
    everySecond_ list 1

Теперь вы вызываете everySecond [foo, bar, baz], и он работает нормально, в основном по умолчанию начальный индекс равен 1.

Еще более простой способ сделать это - вообще не отслеживать индекс, а использовать логическое значение (True / False). Вы начинаете с False, и вместо проверки делимости на 2 вы просто проверяете логическое значение. Если это True, вы сохраняете элемент и снова вызываете функцию с False; если False, вы игнорируете элемент и снова вызываете функцию с True.

2
Ryan Plant 27 Ноя 2016 в 08:22

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

takeEvenIndexes : List a -> List a
takeEvenIndexes l =
  l
  |> List.indexedMap (\ i x -> if i % 2 == 0 then Just x else Nothing)
  |> List.filterMap identity

indexedMap функция похожа на map, но вы также можете зависеть от индекса значения. И filterMap похожа на карту, но вы можете отбросить некоторые значения, вернув Nothing. Здесь он применяется к {{X4} }, потому что фильтрация уже была предварительно вычислена в предыдущей строке.

4
Zimm i48 27 Ноя 2016 в 18:19