Подтвердить что ты не робот

Как создать массив уникальных объектов в Swift

Как создать уникальный список объектов на языке Swift, например NSSet и NSMutableSet в Objective-C.

4b9b3361

Ответ 1

С Swift 1.2 (Xcode 6.3 beta) Swift имеет собственный тип набора. Из примечаний к выпуску:

Включена новая структура данных Set, которая предоставляет общий сбор уникальных элементов, с полной семантикой значений. Это мосты с NSSet, обеспечивая функциональность, аналогичную Array и Dictionary.

Вот несколько простых примеров использования:

// Create set from array literal:
var set = Set([1, 2, 3, 2, 1])

// Add single elements:
set.insert(4)
set.insert(3)

// Add multiple elements:
set.unionInPlace([ 4, 5, 6 ])
// Swift 3: set.formUnion([ 4, 5, 6 ])

// Remove single element:
set.remove(2)

// Remove multiple elements:
set.subtractInPlace([ 6, 7 ])
// Swift 3: set.subtract([ 6, 7 ])

print(set) // [5, 3, 1, 4]

// Test membership:
if set.contains(5) {
    print("yes")
}

но доступно гораздо больше доступных методов.

Обновление: Наборы теперь также задокументированы в "Типы коллекций" в документации Swift.

Ответ 2

Вы можете использовать любой класс Objective-C в Swift:

var set = NSMutableSet()
set.addObject(foo)

Ответ 3

У Свифта нет понятия множеств. Использование NSMutableSet в Swift может быть медленнее, чем использование Dictionary, которое содержит фиктивные значения. Вы можете сделать это:

var mySet: Dictionary<String, Boolean> = [:]
mySet["something"]= 1

Затем просто перебирайте ключи.

Ответ 5

extension Array where Element: Hashable {
    var setValue: Set<Element> {
        return Set<Element>(self)
    }
}

let numbers = [1,2,3,4,5,6,7,8,9,0,0,9,8,7]
let uniqueNumbers = numbers.setValue    // {0, 2, 4, 9, 5, 6, 7, 3, 1, 8}

let names = ["John","Mary","Steve","Mary"]
let uniqueNames = names.setValue    // {"John", "Mary", "Steve"}

Ответ 6

Я думал, что структура с внутренним Словарем будет способом. Я только начал использовать его, поэтому он не завершен, и я пока не знаю о производительности.

struct Set<T : Hashable>
{
    var _items : Dictionary<T, Bool> = [:]

    mutating func add(newItem : T) {
        _items[newItem] = true
    }

    mutating func remove(newItem : T) {
        _items[newItem] = nil
    }

    func contains(item: T) -> Bool {
        if _items.indexForKey(item) != nil { return true } else { return false }
    }

    var items : [T] { get { return [T](_items.keys) } }
    var count : Int { get { return _items.count } }
}

Ответ 7

Фактически вы можете создать объект Set довольно легко (в отличие от GoZoner, есть встроенный метод содержит):

class Set<T : Equatable> {
    var items : T[] = []

    func add(item : T) {
        if !contains(items, {$0 == item}) {
            items += item
        }
    }
}

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

@assignment @infix func += <T : Equatable> (inout set : Set<T>, items : T[]) -> Set<T> {
    for item in items {
        set.add(item)
    }
    return set
}

Ответ 8

Всегда в таком случае критический фактор - это то, как сравнивать объекты и какие типы объектов входят в набор. Использование словаря Swift, где объекты Set являются клавишами словаря, может быть проблемой, основанной на ограничениях на тип ключа (String, Int, Double, Bool, novalue перечисления или хеширование).

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

// When T is only Equatable
class Set<T: Equatable> {
  var items = Array<T>()

  func hasItem (that: T) {
   // No builtin Array method of hasItem... 
   //   because comparison is undefined in builtin Array   
   for this: T in items {
     if (this == that) {
       return true
     }
   }
   return false
  }

  func insert (that: T) {
    if (!hasItem (that))
      items.append (that)
  }
}

Вышеприведенный пример построения Swift Set; в примере используются объекты, которые являются только Equatable, которые, хотя общий случай, не обязательно приводят к эффективным реализациям Set (сложность поиска (O (N) - пример выше).

Ответ 9

Итак, я думаю, что создание набора с массивом - ужасная идея - O (n) - временная сложность этого набора.

Я собрал хороший набор, который использует словарь: https://github.com/evilpenguin/Swift-Stuff/blob/master/Set.swift

Ответ 10

Я написал функцию для решения этой проблемы.

public func removeDuplicates<C: ExtensibleCollectionType where C.Generator.Element : Equatable>(aCollection: C) -> C {
    var container = C()

    for element in aCollection {
        if !contains(container, element) {
            container.append(element)
        }
    }

    return container
}

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

Вы также можете передать Dictionary, String или что-либо, соответствующее ExtensibleCollectionType протоколу, если хотите.

Ответ 11

Особый случай для классов, производных от NSObject

учитывая, что по умолчанию соответствие Equitable является мусором, вам лучше убедиться, что вы предоставили правильное

static func == (lhs: YourClassDerivedFromNSObject, rhs: YourClassDerivedFromNSObject) -> Bool {

реализация, чтобы вы хотели выщипывание дубликатов, вставленных в Set