Использование map: Одна мысль, множество данных

Функция map проецирует одно правило преобразования на всю коллекцию данных. Избавьтесь от утомительной итерации и узнайте, как последовательно применять одну идею ко многим фрагментам данных, создавая новые формы информации.

В Лиспекс вы часто будете работать со списками данных. Вместо использования традиционных циклов, Лиспекс предоставляет мощные функции высшего порядка для обработки списков чистым, функциональным способом. Это руководство знакомит с двумя наиболее важными функциями: map и filter.

Преобразование каждого элемента с помощью map

Что если у вас есть список чисел и вы хотите создать новый список, где каждое число удвоено? Это идеальная задача для map.

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

Синтаксис: (map FUNCTION LIST)

Пример: Удвоение чисел

(define numbers (list 10 20 30 40))

(define doubled-numbers
  (map (lambda (x) (* x 2)) numbers))

;; Теперь значение doubled-numbers равно (list 20 40 60 80)
;; Исходный список `numbers` остается без изменений.

В этом примере функция (lambda (x) (* x 2)) применяется к каждому элементу и создаёт новый список.

Выбор элементов с помощью filter

А что если у вас есть список чисел, и вы хотите оставить только те, которые являются четными? Это задача для filter.

Функция filter принимает предикат (возвращает #t или #f) и список. Она применяет предикат к каждому элементу и возвращает новый список, содержащий только элементы, для которых предикат вернул #t.

Синтаксис: (filter PREDICATE_FUNCTION LIST)

Пример: Поиск четных чисел

(define numbers (list 1 2 3 4 5 6 7 8))

(define even-numbers
  (filter (lambda (n) (= (modulo n 2) 0)) numbers))

;; Теперь значение even-numbers равно (list 2 4 6 8)

Совместное использование: конвейер обработки данных

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

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

(define all-scores (list 2 8 5 10 3 7))

;; Шаг 1: Оставляем только оценки больше 5.
(define high-scores (filter (lambda (score) (> score 5)) all-scores))
;; high-scores ⇒ (list 8 10 7)

;; Шаг 2: Формируем строки (используем string-append).
(define report
  (map (lambda (score)
         (string-append "High score: " (number->string score)))
       high-scores))
;; Теперь значение report равно (list "High score: 8" "High score: 10" "High score: 7")

Вы даже можете вкладывать эти вызовы для более лаконичного кода:

(map (lambda (score) (string-append "High score: " (number->string score)))
     (filter (lambda (score) (> score 5))
             (list 2 8 5 10 3 7)))

Заключение

Используя map и filter, вы можете писать выразительный, читаемый и мощный код для манипулирования данными без необходимости в традиционных циклах. Этот функциональный подход является краеугольным камнем языка Лиспекс.