Cómo crear una matriz de lista de objetos únicos en Swift
nsset (10)
A partir de Swift 1.2 (Xcode 6.3 beta), Swift tiene un tipo de conjunto nativo. De las notas de la versión:
Se incluye una nueva estructura de datos de
Set
que proporciona una colección genérica de elementos únicos, con semántica de valor completo. SeNSSet
conNSSet
, proporcionando una funcionalidad análoga aArray
yDictionary
.
Aquí hay algunos ejemplos de uso simples:
// 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")
}
pero hay muchos más métodos disponibles.
Actualización: los conjuntos ahora también están documentados en el capítulo "Tipos de colección" de la documentación de Swift.
¿Cómo podemos crear una lista de objetos única en lenguaje Swift como NSSet
& NSMutableSet
en Objective-C?
Así que creo que crear un conjunto con un arreglo es una idea terrible: O (n) es la complejidad del tiempo de ese conjunto.
He creado un conjunto agradable que utiliza un diccionario: https://github.com/evilpenguin/Swift-Stuff/blob/master/Set.swift
Creé un tipo de Set
extenso similar al Array
y el Dictionary
integrados - aquí están las publicaciones de blog uno y dos y un repositorio de GitHub:
En realidad, puedes crear un objeto Set bastante fácil (en contradicción con GoZoner, hay un método incorporado que contiene):
class Set<T : Equatable> {
var items : T[] = []
func add(item : T) {
if !contains(items, {$0 == item}) {
items += item
}
}
}
y quizás quieras declarar un operador personalizado:
@assignment @infix func += <T : Equatable> (inout set : Set<T>, items : T[]) -> Set<T> {
for item in items {
set.add(item)
}
return set
}
Escribí una función para resolver este problema.
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
}
Para usarlo, simplemente pase una matriz que contenga elementos duplicados a esta función. Y luego devolverá una matriz garantizada por exclusividad.
También puede pasar un Dictionary
, String
o cualquier cosa conforme al protocolo ExtensibleCollectionType
si lo desea.
Pensé que una estructura con un diccionario interno sería el camino a seguir. Recién comencé a usarlo, por lo que no está completo y aún no tengo idea de su rendimiento.
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 } }
}
Puedes usar cualquier clase Objective-C en Swift:
var set = NSMutableSet()
set.addObject(foo)
Siempre en tal caso, el factor crítico es cómo comparar objetos y qué tipos de objetos entran en el Conjunto. Usar un Swift Dictionary, donde los objetos Set son las teclas del diccionario, podría ser un problema basado en las restricciones del tipo de tecla (String, Int, Double, Bool, Enumerations sin valor o hashable).
Si puede definir una función hash en su tipo de objeto, puede usar un diccionario. Si los objetos se pueden ordenar , entonces podrías definir un árbol. Si los objetos son solo comparables con ==
, necesitarás iterar sobre los elementos establecidos para detectar un objeto preexistente.
// 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)
}
}
Lo anterior es un ejemplo de cómo construir un Swift Set
; el ejemplo usó objetos que son solo Equatable
, lo que, si bien es un caso común, no conduce necesariamente a implementaciones de Set
eficientes (complejidad de búsqueda O (N)), lo anterior es un ejemplo).
Swift no tiene concepto de conjuntos. Usar NSMutableSet
en Swift podría ser más lento que usar un Dictionary
que contenga valores ficticios. Podrías hacer esto:
var mySet: Dictionary<String, Boolean> = [:]
mySet["something"]= 1
Luego solo itera sobre las teclas.
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"}