Avatar ·

Как объединить или слить массивы в Swift? (полное руководство)

Всем привет! Я новичок в Swift и пишу своё первое приложение. Столкнулся с простой, казалось бы, задачей: у меня есть два массива с именами пользователей, и мне нужно их объединить в один общий массив. Вот что я пробовал: ```swift let teamA = ["Анна", "Борис", "Виктор"] let teamB = ["Глеб", "Дарья", "Елена"] let mergedArray = teamA + teamB // это работает, но правильно ли? ``` Но у меня есть несколько вопросов: 1. Это самый правильный способ объединения массивов? 2. Что если массивы имеют разные типы? Например, один массив содержит строки, а другой — числа? 3. Как быть, если нужно объединить больше двух массивов, например, 5-10 штук? 4. Есть ли разница между объединением массивов и их слиянием (merge)? Я слышал, что в Swift есть метод `joined()` — он делает то же самое? 5. Что если я хочу не просто склеить массивы, а объединить их без дубликатов (как в математическом объединении множеств)? Буду очень благодарен за подробное объяснение с примерами. Хочу понять не только "как", но и "почему" работает тот или иной способ. Спасибо! <<>>

Основной способ: оператор +

Да, ваш способ с оператором + — это самый простой и популярный метод объединения массивов в Swift. Он создаёт новый массив, содержащий все элементы первого массива, за которыми следуют все элементы второго. Это работает для любых массивов одного типа.

let teamA = ["Анна", "Борис", "Виктор"]
let teamB = ["Глеб", "Дарья", "Елена"]
let mergedArray = teamA + teamB
// ["Анна", "Борис", "Виктор", "Глеб", "Дарья", "Елена"]

Объединение массивов разных типов

Если массивы имеют разные типы, напрямую их объединить не получится — компилятор выдаст ошибку. Решение: привести элементы к общему типу (например, к строке):

let stringArray = ["a", "b", "c"]
let intArray = [1, 2, 3]
let merged = stringArray + intArray.map { String($0) }
// ["a", "b", "c", "1", "2", "3"]

Объединение нескольких массивов

Для трёх и более массивов можно:

  • Цепочка операторов + (просто, но создаёт промежуточные массивы):
let result = teamA + teamB + ["Жанна", "Захар"] + ["Игорь"]
  • Метод flatMap / reduce (для динамического списка массивов):
let arrays = [teamA, teamB, ["Жанна"], ["Игорь", "Кира"]]
let combined = arrays.flatMap { $0 }
// ["Анна", "Борис", "Виктор", "Глеб", "Дарья", "Елена", "Жанна", "Игорь", "Кира"]

Метод append(contentsOf:) — для изменяемых массивов

Если массив объявлен через var, можно добавлять элементы из другого массива без создания нового:

var mutableTeam = teamA
mutableTeam.append(contentsOf: teamB)
// mutableTeam теперь ["Анна", "Борис", "Виктор", "Глеб", "Дарья", "Елена"]

Это эффективнее, чем +, так как не копирует весь первый массив.

Метод joined() и его отличие

joined() — это метод из протокола Sequence, который работает с массивами массивов. Он не создаёт новый массив, а возвращает ленивую последовательность (FlattenSequence). Чтобы получить массив, нужно обернуть в Array():

let arrayOfArrays = [teamA, teamB]
let flat = Array(arrayOfArrays.joined())
// ["Анна", "Борис", "Виктор", "Глеб", "Дарья", "Елена"]

По сути, joined() делает то же самое, что flatMap { $0 }, но может быть чуть эффективнее для больших коллекций.

Объединение без дубликатов (как множество)

Если нужно получить массив уникальных элементов, используйте Set:

let teamA = ["Анна", "Борис", "Виктор"]
let teamB = ["Борис", "Дарья", "Виктор"]
let uniqueArray = Array(Set(teamA + teamB))
// ["Виктор", "Дарья", "Борис", "Анна"] (порядок может быть любым!)

⚠️ Важно: Set не сохраняет порядок элементов. Если порядок важен, используйте расширение:

extension Array where Element: Hashable {
    func uniqued() -> [Element] {
        var seen = Set()
        return filter { seen.insert($0).inserted }
    }
}
let orderedUnique = (teamA + teamB).uniqued()
// ["Анна", "Борис", "Виктор", "Дарья"]

Производительность

  • Оператор +: O(n+m) по времени и памяти (создаётся новый массив).
  • append(contentsOf:): O(n+m) по времени, но может быть быстрее при частом изменении (меньше копирований).
  • flatMap / joined: O(n*m) в худшем случае, но для простых массивов — O(n+m).

Итог

Для большинства случаев используйте + (для констант) или append(contentsOf:) (для переменных). Если нужны уникальные элементы — комбинация с Set или расширение uniqued(). Для многих массивов — flatMap или joined().

<<>>

Альтернативный подход: использование Sequence и reduce

Если вы работаете с большим количеством массивов или хотите более функциональный стиль, можно использовать reduce:

let allTeams = [teamA, teamB, ["Жанна"], ["Игорь"]]
let merged = allTeams.reduce([], +)
// ["Анна", "Борис", "Виктор", "Глеб", "Дарья", "Елена", "Жанна", "Игорь"]

Этот способ эквивалентен flatMap, но может быть более читаемым для некоторых разработчиков.

Расширение для удобства

Вы можете добавить кастомный метод в Array для объединения нескольких массивов:

extension Array {
    static func concatenate(_ arrays: [Element]...) -> [Element] {
        arrays.flatMap { $0 }
    }
}
let mergedCustom = Array.concatenate(teamA, teamB, ["Тест"])
// ["Анна", "Борис", "Виктор", "Глеб", "Дарья", "Елена", "Тест"]

Когда какой метод выбрать?

  • + — для 2–3 массивов, когда важна краткость.
  • append(contentsOf:) — при работе с var массивами.
  • flatMap / joined — для коллекции массивов.
  • reduce — если вы предпочитаете функциональный стиль.

Все эти методы имеют одинаковую сложность O(n), поэтому выбирайте по читаемости кода.