ГоловнаВсі публікаціїКатегоріїПро проєкт

Як працює метод map в Ruby? Огляд роботи методу з прикладами

Обкладинка нотатки: Як працює метод map в Ruby? Огляд роботи методу з прикладами
Зміст дописунатисність на посилання, щоб перейти до потрібного місця
Метод map є одним із найуживаніших методів у Ruby, що використовується для обробки колекцій. Він дозволяє застосувати блок коду до кожного елементу колекції і повернути нову колекцію з результатами виконання блоку. Насправді це і все пояснення. Але будь-яка інформація засвоюється краще не на абстракціях, а на простих і реальних прикладах. Тож розглянемо метод map трохи детальніше.

Як працює map

Метод map приймає блок, який виконується для кожного елементу колекції. Результати виконання цього блоку збираються в новий масив, який і повертається методом map.
Виконаємо збільшення кожного елементу масиву на 1 (інкремент)
numbers = [1, 2, 3, 4, 5]
incremented_numbers = numbers.map { |n| n + 1 }

incremented_numbers

Результат
=> [2, 3, 4, 5, 6]
Якщо спрощено:
Ми маємо змінну numbers, яка містить в собі масив елементів (колекція елементів) [1, 2, 3, 4, 5].
Далі ми створюємо змінну incremented_numbers та записуємо в неї результат виконання методу map.
Розглянемо конструкцію map:
numbers.map { |n| n + 1 }

# numbers - наша змінна (колекція)
# .map - виклик методу на змінній
# { |n| n + 1 } - блок, який буде виконано для кожного елементу колекції
Тут треба розглянути сам блок:
{ |n| n + 1 }
  • {} - фігурні дужки: Це тіло блоку, де міститься код, який буде виконано для кожного елементу масиву.
  • |n| - змінна: Це параметр блоку. Кожен елемент масиву передається в цю змінну один за одним.
  • n + 1: Це вираз, що виконується для кожного елементу. Він додає 1 до значення змінної n.
Коли ми виконуємо numbers.map { |n| n + 1 }, ось що відбувається:
Для першого елементу 1:
  • n стає 1
  • Виконується 1 + 1
  • Результат 2 додається до нового масиву
Для другого елементу 2:
  • n стає 2
  • Виконується 2 + 1
  • Результат 3 додається до нового масиву
І так далі для кожного елементу масиву. Новий масив записуємо у змінну incremented_numbers та дивимось її зміст
numbers = [1, 2, 3, 4, 5]
incremented_numbers = numbers.map { |n| n + 1 }
incremented_numbers

Результат
=> [2, 3, 4, 5, 6]
А що станеться зі змінною numbers? Нічого, вона залишається незмінною.
Ще один приклад:
words = ["hello", "world", "ruby"]
new_words = words.map { |word| word.upcase }

new_words
=> ["HELLO", "WORLD", "RUBY"]
words
=> ["hello", "world", "ruby"]
Метод upcase модифікує літери (робить великими). Тож змінна new_words має модифіковані слова, а words залишається незмінною.
Доречі, в цих прикладах ми використовуємо конструкцію блоку у фігурних дужка. Блок також можна передавати через do ... end (у випадках, коли код задовгий і непогано б було його розділити на декілька рядків). Тобто:
numbers.map { |n| n + 1 }

теж саме що й

numbers.map do |n| 
  n + 1
end
Ну й приклад з передачею результату у змінну:
incremented_numbers_braces = numbers.map { |n| n + 1 }

incremented_numbers_do_end = numbers.map do |n| 
  n + 1
end
Ще один приклад, але будемо модифікувати hash
hash = { a: 1, b: 2, c: 3 }
incremented_hash = hash.map { |key, value| [key, value + 1] }

incremented_hash
=> [[:a, 2], [:b, 3], [:c, 4]]
Але є нюанс. Виконання map повертає нам Array (масив). Тож нам треба конвертнути Array у Hash (за допомогою методу .to_h).
incremented_hash = incremented_hash.to_h

incremented_hash
=> {:a=>2, :b=>3, :c=>4}
Я думаю, що в конструкції hash.map { |key, value| [key, value + 1] } доволі зрозуміло, що ми беремо key та value з кожного елементу хешу та повертаємо таку конструкцію [key, value + 1].
Тобто результатом виконня map для елементу буде повернення масиву, де перший елемент - key, а другий - модифіковане value (value + 1).
Результат виконання на всій колекції такий:
incremented_hash
=> [[:a, 2], [:b, 3], [:c, 4]]
Масив масивів. Які вже потім ми конвертуємо у hash (виклик to_h).

map! - модифікує оригінальний масив

Знак оклику доданий до методу map означає, що оригінальна колекція (змінна) буде модифікована. Такий тип виклику методу треба використовувати обережно.
numbers = [1, 2, 3, 4, 5]
numbers.map! { |n| n + 1 }

numbers
=> [2, 3, 4, 5, 6]
  • map: Створює новий масив, залишаючи оригінальний масив незмінним.
  • map!: Модифікує оригінальний масив, змінюючи його елементи на місці.

Чому така назва методу (map)?

Назва map походить від математичної операції "відображення" (mapping), де кожен елемент одного набору "відображається" у відповідний елемент іншого набору. В програмуванні це означає застосування функції або блоку коду до кожного елементу колекції, щоб створити нову колекцію з результатами цих застосувань.
Метод map у Ruby є потужним інструментом для обробки колекцій, що дозволяє легко створювати нові колекції, перетворюючи кожен елемент за допомогою заданого блоку. Він має додаткові можливості (наприклад використання індексів) альтернативи (наприклад each) і навіть синоніми (collect). Але метою цього допису було пояснити принцип роботи методу map без сильних ускладнень. Інші штуки розглянемо в наступних дописах про Ruby. 
Як зробити пустий git commit?
28.06.2024 08:33

Як зробити пустий git commit?

meme code
meme code@memecode
Ruby-бібліотека Gosu для створення 2D-ігор
29.06.2024 08:48

Ruby-бібліотека Gosu для створення 2D-ігор

meme code
meme code@memecode
Gosu Ruby Tutorial - пройдемось по офіційній документації
03.07.2024 11:50

Gosu Ruby Tutorial - пройдемось по офіційній документації

meme code
meme code@memecode
Пишемо демо-гру Drones vs Zombies (Gosu / Ruby)
12.07.2024 12:17

Пишемо демо-гру Drones vs Zombies (Gosu / Ruby)

meme code
meme code@memecode
Як пофіксити збій Windows викликаний CrowdStrike?
19.07.2024 13:53

Як пофіксити збій Windows викликаний CrowdStrike?

meme code
meme code@memecode
Що означає .map(&:name) в Ruby?
28.07.2024 11:18

Що означає .map(&:name) в Ruby?

meme code
meme code@memecode
Що означає крапка на початку файлу(.gitignore, .DS_Store, .bashrc тощо)?
02.08.2024 13:15

Що означає крапка на початку файлу(.gitignore, .DS_Store, .bashrc тощо)?

meme code
meme code@memecode
Що таке .gitignore? Для чого потрібен та як використовувати
02.08.2024 14:58

Що таке .gitignore? Для чого потрібен та як використовувати

meme code
meme code@memecode
Як видалити файл .DS_Store з Git репозиторію?
02.08.2024 19:34

Як видалити файл .DS_Store з Git репозиторію?

meme code
meme code@memecode
Що таке ідемпотентний метод?
21.08.2024 20:57

Що таке ідемпотентний метод?

meme code
meme code@memecode
Що таке репозиторій?
21.08.2024 21:25

Що таке репозиторій?

meme code
meme code@memecode
Що таке коміт (commit) у контексті програмування та SCM / Git?
21.08.2024 21:37

Що таке коміт (commit) у контексті програмування та SCM / Git?

meme code
meme code@memecode