¿Cuándo es mejor utilizar un NSSet sobre un NSArray?


Respuestas:


173

Cuando el orden de los elementos de la colección no es importante, los conjuntos ofrecen un mejor rendimiento para encontrar elementos en la colección.

La razón es que un conjunto usa valores hash para encontrar elementos (como un diccionario), mientras que una matriz tiene que iterar sobre todo su contenido para encontrar un objeto en particular.


9
log (1) vs log (n)
rohan-patel

25
@ rohan-patel Correcto es O (1) vs O (n)
Mansurov Ruslan

1
Si se ordena: O (1) vs O (logn) ya que la búsqueda binaria es aplicable. Si no está ordenado, entonces O (1) vs O (n)
baskInEminence

180

La imagen de la documentación de Apple lo describe muy bien:

Colecciones Objective-C

Arrayes una secuencia ordenada (el orden se mantiene cuando agrega) de elementos

[array addObject:@1];
[array addObject:@2];
[array addObject:@3];
[array addObject:@4];
[array addObject:@6];
[array addObject:@4];
[array addObject:@1];
[array addObject:@2];

[1, 2, 3, 4, 6, 4, 1, 2]

Setes una lista de elementos distinta (sin duplicados) y desordenada

[set addObject:@1];
[set addObject:@2];
[set addObject:@3];
[set addObject:@4];
[set addObject:@6];
[set addObject:@4];
[set addObject:@1];
[set addObject:@2];

[1, 2, 6, 4, 3]

2
En su ejemplo, está agregando primitivas a una matriz y un conjunto. Tampoco es posible porque solo pueden contener objetos.
FreeAsInBeer

10
Gracias por tu edición @Zaheer, pero en realidad no era válida. No estaba agregando primitivas. Estaba agregando literales.
James Webster

Gran explicación :) +1 :)
Karun

1
¡Amo tu explicación! +1 por eso
rebelión

66

La mejor respuesta es la propia documentación de Apple .

ingrese la descripción de la imagen aquí

La principal diferencia es que NSArrayes para una colección ordenada y NSSetes para una colección desordenada.

Hay varios artículos que hablan sobre la diferencia de velocidad entre los dos, como este . Si está iterando a través de una colección desordenada, NSSetes genial. Sin embargo, en muchos casos, necesitas hacer cosas que solo uno NSArraypuede hacer, por lo que sacrificas la velocidad por esas habilidades.

NSSet

  • Principalmente acceda a elementos por comparación
  • Desordenado
  • No permite duplicados

NSArray

  • Puede acceder a elementos por índice
  • Ordenado
  • Permite duplicados

¡Eso es todo lo que hay que hacer! Avísame si eso ayuda.


No siempre tienes que sacrificarte NSSetpor indexar. Es común utilizar dos estructuras de datos diferentes para los mismos datos. O construye e indexa en esa matriz :) Pero entonces es mejor usar una base de datos que ya lo tenga implementado.
Sulthan

"Construya un índice en esa matriz". No puede crear un índice en un NSSet. Hay muchas técnicas diferentes que puede utilizar. Y si necesita hacer sacrificios tanto en la memoria como en la potencia de procesamiento, entonces lo está haciendo mal.
Sulthan

Dado que la pregunta es sobre NSSety NSArray, mi respuesta es precisa y completa. Sí, puede construir otras estructuras de datos, pero solo estoy comparando estos dos.
woz

Yo voté a favor, pero tu respuesta es incorrecta cuando hablas de sacrificios. Si necesita alguna funcionalidad de NSArrayy alguna funcionalidad de NSSet, la respuesta correcta no es "utilizar NSArrayy sacrificar el rendimiento". La respuesta es combinar ambos o utilizar una estructura de datos diferente.
Sulthan

Habría dicho que la principal diferencia se establece para objetos únicos donde una matriz puede tener duplicados. El aspecto del orden es secundario a ese hecho.
Malhal

12

NSOrderedSet está disponible en iOS 5+, por lo que la principal diferencia es si desea objetos duplicados en la estructura de datos.


9

NSArray :

  1. Recopilación ordenada de datos
  2. Permite duplicados
  3. Es un objeto de tipo colección

NSSet :

  1. Recopilación desordenada de datos
  2. No permite duplicados
  3. También es objeto de tipo colección

7

Una matriz se utiliza para acceder a elementos por su índice. Cualquier elemento se puede insertar en la matriz varias veces. Las matrices mantienen el orden de sus elementos.

Un conjunto se usa básicamente solo para verificar si el artículo está en la colección o no. Los artículos no tienen concepto de orden ni indexación. No puede tener un artículo en un conjunto dos veces.

Si una matriz quiere verificar si contiene un elemento, tiene que verificar todos sus elementos. Los conjuntos están diseñados para utilizar algoritmos más rápidos.

Puedes imaginar un conjunto como un diccionario sin valores.

Tenga en cuenta que la matriz y el conjunto no son las únicas estructuras de datos. Hay otros, por ejemplo, Cola, Pila, Montón, Montón de Fibonacci. Recomendaría leer un libro sobre algoritmos y estructuras de datos.

Consulte wikipedia para obtener más información.


En realidad, solo es necesario comprobar una matriz hasta el punto en que se encuentra el elemento. Si el elemento ESTÁ en la matriz, muy rara vez será necesario verificar todos los elementos.
FreeAsInBeer

Sí, como dice "si el elemento ESTÁ en la matriz". Si espera esto, no tiene que verificar si está ahí o no. La complejidad de la containsoperación es O(n). El número de comparaciones cuando no está en la matriz es n. El número medio de comparaciones cuando el objeto está en la matriz es n/2. Incluso si se encuentra el objeto, el rendimiento es terrible.
Sulthan

El rendimiento solo sería terrible con una gran variedad. Si supiera que la matriz podría volverse bastante grande, existen formas de mejorar el rendimiento de la matriz, como usar una matriz de matrices.
FreeAsInBeer

Si la operación de igualdad es cara, verá la diferencia incluso en matrices con 3 elementos. Y el mismo comportamiento que una matriz grande puede suceder si repites mucho la operación (por ejemplo, usa la operación en un ciclo 'for'). ¿Ha oído hablar de la complejidad amortizada? La complejidad sigue siendo lineal y el rendimiento es terrible en comparación con un conjunto (generalmente con una complejidad constante).
Sulthan

Obviamente habrá una diferencia, solo estoy diciendo que la notación o grande es exponencial; con arreglos pequeños, la diferencia será minúscula. Además, los NSArrays tienen otras ventajas de velocidad sobre NSSets. Como siempre, es una compensación.
FreeAsInBeer

5
NSArray *Arr;
NSSet *Nset;

Arr=[NSArray arrayWithObjects:@"1",@"2",@"3",@"4",@"2",@"1", nil];
Nset=[NSSet setWithObjects:@"1",@"2",@"3",@"3",@"5",@"5", nil];

NSLog(@"%@",Arr);
NSLog(@"%@",Nset);

la matriz

2015-12-04 11: 05: 40.935 [598: 15730] (1, 2, 3, 4, 2, 1)

el conjunto

2015-12-04 11: 05: 43.362 [598: 15730] {(3, 1, 2, 5)}


4

Las principales diferencias ya se han dado en otras respuestas.

Solo me gustaría señalar que debido a la forma en que se implementan los conjuntos y diccionarios (es decir, usando hashes), uno debe tener cuidado de no usar objetos mutables para las claves.

Si una clave está mutada, el hash (probablemente) también cambiará, apuntando a un índice / depósito diferente en la tabla hash. El valor original no se eliminará y, de hecho, se tendrá en cuenta al enumerar o preguntar a la estructura su tamaño / recuento.

Esto puede provocar algunos errores realmente difíciles de localizar.


3

Aquí puede encontrar una comparación bastante completa de las estructuras de datos NSArrayy NSSet.

Breves conclusiones:

Sí, NSArray es más rápido que NSSet para simplemente mantener e iterar. Tan poco como un 50% más rápido para construir y hasta un 500% más rápido para iterar. Lección: si solo necesita iterar contenidos, no use un NSSet.

Por supuesto, si necesita probar la inclusión, trabaje duro para evitar NSArray. Incluso si necesita pruebas de iteración e inclusión, probablemente debería elegir un NSSet. Si necesita mantener su colección ordenada y también probar su inclusión, entonces debería considerar mantener dos colecciones (una NSArray y una NSSet), cada una con los mismos objetos.

NSDictionary es más lento de construir que NSMapTable, ya que necesita copiar los datos clave. Lo compensa siendo más rápido de buscar. Por supuesto, los dos tienen capacidades diferentes, por lo que la mayoría de las veces, esta determinación debe basarse en otros factores.


Si bien esto teóricamente puede responder a la pregunta, sería preferible incluir aquí las partes esenciales de la respuesta y proporcionar el enlace como referencia.
Tunaki

2

Por lo general, usaría un Conjunto cuando la velocidad de acceso es esencial y el orden no importa , o está determinado por otros medios (a través de un predicado o descriptor de clasificación). Core Data, por ejemplo, usa conjuntos cuando se accede a los objetos administrados a través de una relación a muchos


1

Solo para agregar un poco, uso el conjunto a veces solo para eliminar duplicados de la matriz como: -

NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.