Удаление дубликатов из массива в Swift: туториал для новичков

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как избавиться от дубликатов в массиве Swift: понятное руководство для начинающих

Вы когда-нибудь сталкивались с ситуацией, когда ваш массив в Swift превращался в "свалку" повторяющихся данных? Если да, то вы не одиноки. Вопрос "Removing duplicate elements from an array in Swift" на Stack Overflow собрал тысячи просмотров — и это неудивительно. Работа с дубликатами — одна из самых частых задач, с которой сталкивается каждый разработчик, будь то новичок или профи. Сегодня мы раз и навсегда разберемся, как элегантно и эффективно удалять повторяющиеся элементы из массива в Swift, используя проверенные методы и реальные примеры кода.

Почему это важно: практические сценарии

Представьте, что вы пишете приложение для управления контактами. Пользователь импортирует список из 1000 записей, но в нем 200 дубликатов. Или вы работаете с данными из API, где один и тот же товар приходит несколько раз. Дубликаты не только захламляют интерфейс, но и могут привести к логическим ошибкам, увеличению времени обработки и путанице в данных. Умение чистить массивы — это база, которая сэкономит вам часы отладки.

В этом туториале мы рассмотрим несколько подходов: от простого использования Set до более продвинутых методов с сохранением порядка элементов и работой с пользовательскими типами данных. Поехали!

Метод 1: Использование Set — самый быстрый и простой способ

Самый популярный ответ на Stack Overflow для удаления дубликатов из массива в Swift — это использование структуры Set. Set — это неупорядоченная коллекция уникальных элементов. Преобразуя массив в Set, мы автоматически избавляемся от всех повторений, а затем преобразуем его обратно в массив.

Пример кода:

let numbers = [1, 2, 3, 2, 4, 5, 1, 3]
let uniqueNumbers = Array(Set(numbers))
print(uniqueNumbers) // Вывод: [5, 2, 3, 1, 4] (порядок может отличаться)

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

Когда использовать Set?

  • Когда порядок элементов не имеет значения.
  • Когда нужно максимально быстрое решение.
  • Когда работаете с примитивными типами (Int, String, Double и т.д.), которые соответствуют протоколу Hashable.

Метод 2: Сохранение порядка с помощью NSOrderedSet

Если вы работаете в проекте, где разрешен Objective-C runtime (например, старые проекты или смешанные кодовые базы), можно использовать NSOrderedSet. Этот класс из Foundation сохраняет порядок добавления и автоматически удаляет дубликаты.

Пример кода:

import Foundation

let names = ["Анна", "Борис", "Анна", "Виктор", "Борис"]
let uniqueNames = NSOrderedSet(array: names).array as! [String]
print(uniqueNames) // Вывод: ["Анна", "Борис", "Виктор"]

Плюсы: порядок сохранен, код короткий. Минусы: используется мост с Objective-C, что может быть излишним для чистого Swift-проекта. Кроме того, NSOrderedSet работает медленнее, чем нативный Set, из-за дополнительных накладных расходов.

Метод 3: Кастомная фильтрация с сохранением порядка (чистый Swift)

Это самый гибкий и рекомендуемый способ для современного Swift. Мы создаем пустой массив для результата и Set для отслеживания уже встреченных элементов. Проходя по исходному массиву, мы добавляем элемент в результат только если его еще нет в Set.

Пример кода:

func removeDuplicates<T: Hashable>(from array: [T]) -> [T] {
    var seen = Set<T>()
    var result = [T]()
    
    for element in array {
        if !seen.contains(element) {
            seen.insert(element)
            result.append(element)
        }
    }
    return result
}

let animals = ["Кошка", "Собака", "Кошка", "Попугай", "Собака", "Хомяк"]
let uniqueAnimals = removeDuplicates(from: animals)
print(uniqueAnimals) // Вывод: ["Кошка", "Собака", "Попугай", "Хомяк"]

Этот метод — золотая середина: он сохраняет порядок, работает быстро (O(n) в среднем) и написан на чистом Swift без сторонних зависимостей. Универсальная функция removeDuplicates работает с любым типом, соответствующим протоколу Hashable.

Альтернатива с использованием reduce

Для любителей функционального стиля Swift можно использовать reduce(into:):

let numbers = [10, 20, 10, 30, 20, 40]
let uniqueNumbers = numbers.reduce(into: [Int]()) { result, element in
    if !result.contains(element) {
        result.append(element)
    }
}
print(uniqueNumbers) // Вывод: [10, 20, 30, 40]

Обратите внимание: этот вариант работает медленнее на больших массивах, так как result.contains(element) имеет сложность O(n) на каждой итерации. Для небольших массивов (до 100 элементов) это приемлемо, но для серьезных объемов лучше использовать предыдущий метод с Set.

Работа с пользовательскими типами данных

А что делать, если ваш массив состоит из объектов собственного класса или структуры? Допустим, у вас есть модель пользователя:

struct User {
    let id: Int
    let name: String
}

По умолчанию структуры не соответствуют протоколу Hashable (хотя в Swift 4.1+ компилятор может автоматически сгенерировать реализацию, если все свойства соответствуют Hashable). Вы можете либо добавить : Hashable к структуре, либо реализовать свою логику сравнения.

Пример с Hashable:

struct User: Hashable {
    let id: Int
    let name: String
}

let users = [
    User(id: 1, name: "Анна"),
    User(id: 2, name: "Борис"),
    User(id: 1, name: "Анна"), // дубликат по id
    User(id: 3, name: "Виктор")
]

let uniqueUsers = Array(Set(users))
print(uniqueUsers.map { $0.name }) // Вывод: ["Борис", "Анна", "Виктор"] (порядок не сохранен)

Но что если вы хотите считать дубликатами только пользователей с одинаковым id, даже если имена отличаются? В этом случае нужно переопределить hash(into:) и ==:

struct User: Hashable {
    let id: Int
    let name: String
    
    func hash(into hasher                

Блоги

Рекомендаций по книгам