Бесплатный курс по Elixir. Зарегистрируйтесь для отслеживания прогресса →

Elixir: Отображение

Так как язык Эликсир является функциональным языком программирования, то в большинстве случаев списки обрабатываются 'классической' тройкой функций map, filter, reduce. Рассмотрим первую функцию map, которая переводится как 'отображение', что полностью отражает суть выполняемой операции:

numbers = [1, 2, 3, 4]

doubled_numbers = Enum.map(numbers, fn (x) -> x * 2 end)
IO.puts(doubled_numbers) # => [2, 4, 6, 8]

users = [%{name: "Igor"}, %{name: "John"}, %{name: "Alice"}, %{name: "Isabella"}]

names = Enum.map(users, &(&1[:name]))
IO.puts(names) # => ["Igor", "John", "Alice", "Isabella"]

# либо с помощью паттерн-матчинга
names = Enum.map(users, fn %{name: name} -> name end)
IO.puts(names) # => ["Igor", "John", "Alice", "Isabella"]

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

numbers = [1, 2, 3]

incremented_numbers = Enum.map(numbers, fn (x) -> x + 1 end)

IO.puts(numbers) # => [1, 2, 3]
IO.puts(incremented_numbers) # => [2, 3, 4]

stringified = Enum.map(numbers, fn (x) -> "Number: #{x}" end)
IO.puts(stringified) # => ["Number: 1", "Number: 2", "Number: 3"]

Так как функция map ожидает первым аргументом список, то мы можем с помощью оператора |> комбинировать несколько преобразований подряд:

numbers = [1, 2, 3, 4]

result =
  numbers
  |> Enum.map(fn (x) -> x + 1 end)
  |> Enum.map(fn (x) -> x * 5 end)
  |> Enum.map(fn (x) -> x / 2 end)
  |> Enum.map(&Float.round/1)

IO.puts(result) # => [5.0, 8.0, 10.0, 13.0]

Задание

Реализуйте функцию zip, которая группирует элементы переданных векторов в подвектора. Если вектора отличаются длиной, то вместо сгрупированного элемента оставьте nil. Для обращения к элементу списка по индексу используйте Enum.at.
Примеры:

Solution.zip([], [])
# => []
Solution.zip([1, 2, 3, 4], [5, 6, 7, 8])
# => [[1, 5], [2, 6], [3, 7], [4, 8]]
Solution.zip([1, 2], [3, 4])
# => [[1, 3], [2, 4]]
Solution.zip([1, 2], [3])
# => [[1, 3], [2, nil]]
Solution.zip([1], [3, 4])
# => [[1, 3], [nil, 4]]
Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

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

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя 🤔

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

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

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

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

Полезное


Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics
Если вы столкнулись с трудностями и не знаете, что делать, задайте вопрос в нашем большом и дружном сообществе