array ios arrays swift

ios - ¿Cómo obtener la lista de elementos comunes de 2 array en Swift?



array filter swift 4 (6)

Conviértalos a Set y use la función intersect ():

let fruitsArray = ["apple", "mango", "blueberry", "orange"] let vegArray = ["tomato", "potato", "mango", "blueberry"] let fruitsSet = Set(fruitsArray) let vegSet = Set(vegArray) let output = Array(fruitsSet.intersect(vegSet))

Tengo dos matrices:

fruitsArray = ["apple", "mango", "blueberry", "orange"] vegArray = ["tomato", "potato", "mango", "blueberry"]

¿Cómo puedo obtener la lista de elementos comunes en esos dos conjuntos que da

ouptput = ["mango", "blueberry"]

No puedo usar if contains(array, string) ya que quiero comparar 2 matrices.


Lo siguiente funciona con swift 4:

let fruitsArray = ["apple", "mango", "blueberry", "orange"] let vegArray = ["tomato", "potato", "mango", "blueberry"] var someHash: [String: Bool] = [:] fruitsArray.forEach { someHash[$0] = true } var commonItems = [String]() vegArray.forEach { veg in if someHash[veg] ?? false { commonItems.append(veg) } } print(commonItems)


También puede usar filter y contains en conjunto:

let fruitsArray = ["apple", "mango", "blueberry", "orange"] let vegArray = ["tomato", "potato", "mango", "blueberry"] // only Swift 1 let output = fruitsArray.filter{ contains(vegArray, $0) } // in Swift 2 and above let output = fruitsArray.filter{ vegArray.contains($0) } // or let output = fruitsArray.filter(vegArray.contains)

Set vs Array para un solo cálculo de elementos comunes

Consideramos el siguiente fragmento de código:

let array1: Array = ... let array2: Array = ... // `Array` let commonElements = array1.filter(array2.contains) // vs `Set` let commonElements = Array(Set(array1).intersection(Set(array2))) // or (performance wise equivalent) let commonElements: Array = Set(array1).filter(Set(array2).contains)

Hice algunos puntos de referencia (artificiales) con Int y String s corto / largo (10 a 100 Character ) (todos generados aleatoriamente). Siempre uso array1.count == array2.count

Obtengo los siguientes resultados:

Si tiene critical #(number of) elements más que critical #(number of) elements es preferible convertir a un Set

data | critical #elements -------------|-------------------- Int | ~50 short String | ~100 long String | ~200

Explicación de los resultados.

El uso del enfoque de Array utiliza la búsqueda de "fuerza bruta" que tiene una complejidad de tiempo O(N^2) donde N = array1.count = array2.count que está en contraste con el enfoque Set O(N) . Sin embargo, la conversión de Array a Set y viceversa es muy costosa para datos grandes, lo que explica el aumento de elementos critical #elements para tipos de datos más grandes.

Conclusión

Para los Array pequeños con aproximadamente 100 elementos, el enfoque Array está bien, pero para los más grandes, debe usar el enfoque Set .

Si desea utilizar esta operación de "elementos comunes" varias veces, es recomendable utilizar Set s solo si es posible (el tipo de elementos debe ser Hashable ).

Observaciones finales

Una conversión de Array a Set es algo costosa, mientras que la conversión de Set a Array es, por el contrario, muy económica.

El uso del filter con .filter(array1.contains) es más rápido en cuanto al rendimiento que .filter{ array1.contains($0) } ya que:

  • el último crea un nuevo cierre ( solo una vez ) mientras que el primero solo pasa un puntero de función
  • para el último, la llamada del cierre crea un marco de pila adicional que cuesta espacio y tiempo ( varias veces : O(N) )

Un método genérico, inspirado en el ejercicio del lenguaje de programación Swift (Swift 3) :

func commonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element] where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element { var common: [T.Iterator.Element] = [] for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { common.append(lhsItem) } } } return common }

Luego, úsalo así:

var a = [3,88,74] var b = [1,3,88] print("commons: /(commonElements(a, b))") --> commons: [3, 88]


Usando Set y también intersección de la siguiente manera:

func findIntersection (firstArray : [Int], secondArray : [Int]) -> [Int] { return [Int](Set<Int>(firstArray).intersection(secondArray)) } print (findIntersection(firstArray: [2,3,4,5], secondArray: [1,2,3]))


No necesita un conjunto (como se ha mencionado en los comentarios anteriores).

En su lugar, podría usar una función genérica , similar a la que Apple usa en su Swift Tour, y así evitar el lanzamiento :

func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> Bool { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false }

Esta función puede tomar dos matrices (SequenceTypes) y si alguno de sus elementos es el mismo, devuelve verdadero.

Simplemente puede modificar esta función genérica para empaquetar una matriz de cadenas y devolverla en su lugar.

Por ejemplo así:

func arrayOfCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> [T.Generator.Element] { var returnArray:[T.Generator.Element] = [] for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { returnArray.append(lhsItem) } } } return returnArray }

Uso como este:

var one = ["test2", "dog", "cat"] var other = ["test2", "cat", "dog"] var result = arrayOfCommonElements(one,other) print(result) //prints [test2, dog, cat]

El beneficio adicional aquí es que esta función también funciona con las mismas matrices escritas. Más tarde, si necesita comparar dos matrices [myCustomObject] , una vez que ambas se ajustan a igual, ¡ya está todo listo ! (juego de palabras previsto)

Editar: (para elementos no comunes) podría hacer algo como esto

func arrayOfNonCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> [T.Generator.Element] { var returnArray:[T.Generator.Element] = [] var found = false for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { found = true break } } if (!found){ returnArray.append(lhsItem) } found = false } for rhsItem in rhs { for lhsItem in lhs { if rhsItem == lhsItem { found = true break } } if (!found){ returnArray.append(rhsItem) } found = false } return returnArray }

Sin embargo, esta implementación es fea.