Определите, какой инвариант по числу элементов сохраняет map при успешно завершившемся преобразовании?
map сохраняет количество элементов: для каждого элемента исходной последовательности он создаёт ровно один результат. Поэтому при успешном полном преобразовании конечной последовательности размер результата равен размеру источника, хотя тип и значения элементов могут измениться.
Функциональный подход отделяет обход данных от операции над каждым элементом. map решает задачу преобразования «один вход — один выход», благодаря чему результат можно рассуждать без анализа конкретной реализации цикла.
Этот контракт особенно полезен по сравнению с операциями, которые могут менять количество элементов: filter отбрасывает элементы, а compactMap дополнительно исключает результаты nil.
Неверное ожидание, что map может пропускать элементы, приводит к ошибкам в бизнес-логике. Например, если нужно сохранить соответствие между исходными записями и DTO, замена map на compactMap незаметно изменит количество записей.
Инвариант действует только при успешном завершении обхода конечной последовательности. Если замыкание выбрасывает ошибку или источник бесконечен и его пытаются обработать целиком, конечный результат не будет получен.
map вызывает переданное замыкание один раз для каждого элемента, который был успешно извлечён из источника. Каждое возвращённое значение добавляется в результат; map не интерпретирует его как признак удаления элемента, даже если это nil, Optional или значение, совпадающее с другим результатом.
У стандартного map результатом обычно является массив, поэтому он не обязан сохранять исходный тип коллекции. Например, преобразование Set может вернуть массив с повторяющимися результатами: уникальность исходных элементов не означает уникальность преобразованных значений.
У ленивой последовательности преобразование представлено ленивой оболочкой: соответствующий результат вычисляется при обходе. Это не отменяет правило «один обработанный вход — один выход», но количество фактически созданных результатов зависит от того, какую часть последовательности запросили.
Сравнение операций:
nil-результаты исключаются;Минимальный пример:
Замыкание меняет тип и значение элементов, но не их количество. Если бы вместо map использовался filter, сохранение размера уже не гарантировалось бы.
Сервис возвращает список из 10 000 записей, и для каждой нужно построить модель отображения. map подходит, если каждая запись обязана породить ровно одну модель; сохранение количества позволяет проверить полноту преобразования.
Вариант с compactMap удобен, если некорректные записи нужно молча исключать, но он скрывает факт потерь. Вариант с filter требует отдельного преобразования и хуже выражает связь «одна запись — одна модель».
Выбранное решение — map для гарантированного одно-к-одному преобразования, а проверку некорректных данных следует выполнять отдельно: например, возвращать ошибку, использовать явный статус обработки или заранее отфильтровывать записи с документированным изменением количества. В результате бизнес-логика не теряет элементы неявно.
1. Сохраняет ли map уникальность элементов Set?
Нет. map у Set возвращает последовательность результатов, обычно массив, и одинаковые преобразованные значения могут появиться несколько раз. Уникальность исходных элементов гарантирует лишь отсутствие одинаковых исходных значений, но не отсутствие одинаковых результатов.
2. Сохраняется ли количество элементов, если замыкание map выбрасывает ошибку?
Гарантия относится к успешно завершившемуся преобразованию. При ошибке обход прекращается, и вызывающий код получает ошибку вместо полного результата; частично построенный массив не становится обычным результатом map.
3. Что происходит с инвариантом для бесконечной последовательности?
Для полного eager-преобразования результат не будет получен, потому что у источника нет конца. Ленивое преобразование позволяет обработать конечный префикс, и для каждого реально обработанного элемента будет создан ровно один результат, но заранее конечный размер всей последовательности неизвестен.