Quando é melhor usar um NSSet em vez de um NSArray?

Respostas:

173

Quando a ordem dos itens na coleção não é importante, os conjuntos oferecem melhor desempenho para localizar itens na coleção.

A razão é que um conjunto usa valores hash para encontrar itens (como um dicionário), enquanto um array tem que iterar todo o seu conteúdo para encontrar um objeto específico.

Ole Begemann
fonte
9
log (1) vs log (n)
rohan-patel
25
@ rohan-patel correto é O (1) vs O (n)
Mansurov Ruslan
1
Se solicitado: O (1) vs O (logn), pois a pesquisa binária é aplicável. Se não ordenado, então O (1) vs O (n)
baskInEminence
180

A imagem da Documentação da Apple o descreve muito bem:

Coleções Objective-C

Arrayé uma sequência ordenada (a ordem é mantida quando você adiciona) 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]

Seté uma lista distinta (sem duplicatas) e não ordenada de elementos

[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]
James Webster
fonte
2
Em seu exemplo, você está adicionando primitivas a uma matriz e a um conjunto. Nada disso é possível porque eles só podem conter objetos.
FreeAsInBeer de
10
Obrigado por sua edição @Zaheer, mas na verdade era inválido. Eu não estava adicionando primitivos. Eu estava adicionando literais.
James Webster
Ótima explicação :) +1 :)
Karun
1
Amei sua explicação! +1 para isso
rebelião de
66

A melhor resposta é a documentação da própria Apple .

insira a descrição da imagem aqui

A principal diferença é que se NSArraytrata de uma coleção ordenada e NSSetde uma coleção não ordenada.

Existem vários artigos por aí que falam sobre a diferença de velocidade entre os dois, como este . Se você estiver iterando em uma coleção não ordenada, NSSeté ótimo. No entanto, em muitos casos, você precisa fazer coisas que apenas um NSArraypode fazer, então você sacrifica a velocidade por essas habilidades.

NSSet

  • Acesse principalmente itens por comparação
  • Não ordenado
  • Não permite duplicatas

NSArray

  • Pode acessar itens por índice
  • Encomendado
  • Permite duplicatas

Isso é tudo que realmente importa! Deixe-me saber se isso ajudar.

woz
fonte
Você não precisa sempre se sacrificar NSSetpor causa da indexação. É comum usar duas estruturas de dados diferentes para os mesmos dados. Ou você constrói e indexa nesse array :) Mas então é melhor usar um banco de dados que já o tenha implementado.
Sulthan
"Construa um índice nessa matriz". Você não pode fazer um índice em um NSSet. Existem muitas técnicas diferentes que você pode usar. E se você precisa fazer sacrifícios em AMBOS a memória e o poder de processamento, então você está fazendo errado.
Sulthan
Como a pergunta é sobre NSSete NSArray, minha resposta é precisa e completa. Sim, você pode construir outras estruturas de dados, mas estou apenas comparando essas duas.
woz
Eu votei positivamente, mas sua resposta está incorreta quando você fala sobre sacrifícios. Se você precisa de alguma funcionalidade de NSArraye de alguma funcionalidade de NSSet, a resposta correta não é "usar NSArraye sacrificar o desempenho". A resposta é combinar ambos ou usar uma estrutura de dados diferente.
Sulthan
Eu diria que a principal diferença é definida para objetos exclusivos onde, como uma matriz, pode haver duplicatas. O aspecto da ordem é secundário a esse fato.
Malhal
12

NSOrderedSet está disponível no iOS 5+, portanto, a principal diferença passa a ser se você deseja duplicar objetos na estrutura de dados.

Jason
fonte
9

NSArray :

  1. Coleta ordenada de dados
  2. Permite duplicatas
  3. É um objeto do tipo coleção

NSSet :

  1. Recolha não ordenada de dados
  2. Não permite duplicatas
  3. É também um objeto de tipo de coleção
iOS Lifee
fonte
7

Uma matriz é usada para acessar itens por seu índice. Qualquer item pode ser inserido na matriz várias vezes. As matrizes mantêm a ordem de seus elementos.

Um conjunto é usado basicamente apenas para verificar se o item está na coleção ou não. Os itens não têm conceito de ordem ou indexação. Você não pode ter um item em um conjunto duas vezes.

Se um array deseja verificar se contém um elemento, ele deve verificar todos os seus itens. Os conjuntos são projetados para usar algoritmos mais rápidos.

Você pode imaginar um conjunto como um dicionário sem valores.

Observe que array e set não são as únicas estruturas de dados. Existem outros, por exemplo, Fila, Pilha, Pilha, Pilha de Fibonacci. Eu recomendaria a leitura de um livro sobre algoritmos e estruturas de dados.

Veja wikipedia para mais informações.

Sulthan
fonte
Na verdade, uma matriz só precisa ser verificada até o ponto em que o item é encontrado. Se o item ESTÁ na matriz, muito raramente todos os itens precisarão ser verificados.
FreeAsInBeer de
Sim, como você diz "se o item ESTÁ na matriz". Se você espera isso, não precisa verificar se existe ou não. A complexidade da containsoperação é O(n). Número de comparações quando não está na matriz n. O número médio de comparações quando o objeto está na matriz é n/2. Mesmo que o objeto seja encontrado, o desempenho é péssimo.
Sulthan
O desempenho só seria péssimo com uma grande variedade. Se você soubesse que o array poderia se tornar muito grande, existem maneiras de melhorar o desempenho do array, como usar um array de arrays.
FreeAsInBeer
Se a operação de igualdade for cara, você verá a diferença mesmo em arrays com 3 itens. E o mesmo comportamento de uma grande matriz pode acontecer quando você repete muito a operação (por exemplo, usar a operação em um ciclo 'para'). Você já ouviu falar sobre complexidade amortizada? A complexidade ainda é linear e o desempenho é péssimo em comparação com um conjunto (geralmente com complexidade constante).
Sulthan
Obviamente haverá uma diferença, estou apenas afirmando que a grande notação o é exponencial; com pequenas matrizes, a diferença será minúscula. Além disso, os NSArrays têm outras vantagens de velocidade em relação aos NSSets. Como sempre, é uma troca.
FreeAsInBeer de
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);

a matriz

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

o conjunto

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

abc221
fonte
4

As principais diferenças já foram dadas em outras respostas.

Gostaria apenas de observar que, devido à maneira como os conjuntos e os dicionários são implementados (ou seja, usando hashes), deve-se ter cuidado para não usar objetos mutáveis ​​para as chaves.

Se uma chave sofrer mutação, o hash (provavelmente) também mudará, apontando para um índice / depósito diferente na tabela hash. O valor original não será excluído e será levado em consideração ao enumerar ou solicitar à estrutura seu tamanho / contagem.

Isso pode levar a alguns bugs muito difíceis de localizar.

joakim
fonte
3

Aqui você pode encontrar uma comparação bastante completa das estruturas de dados NSArraye NSSet.

Conclusões curtas:

Sim, o NSArray é mais rápido do que o NSSet para simplesmente segurar e iterar. Tão pouco quanto 50% mais rápido para construir e até 500% mais rápido para iterar. Lição: se você só precisa iterar o conteúdo, não use um NSSet.

Claro, se você precisar testar para inclusão, trabalhe duro para evitar NSArray. Mesmo se você precisar de testes de iteração e inclusão, provavelmente ainda deve escolher um NSSet. Se você precisa manter sua coleção ordenada e também testar para inclusão, você deve considerar manter duas coleções (um NSArray e um NSSet), cada uma contendo os mesmos objetos.

NSDictionary é mais lento para construir do que NSMapTable - uma vez que precisa copiar os dados-chave. Isso compensa por ser mais rápido de pesquisar. Obviamente, os dois têm capacidades diferentes, portanto, na maioria das vezes, essa determinação deve ser feita com base em outros fatores.

Che
fonte
Embora isso possa teoricamente responder à pergunta, seria preferível incluir as partes essenciais da resposta aqui e fornecer o link para referência.
Tunaki
2

Normalmente, você usaria um Conjunto quando a velocidade de acesso fosse essencial e a ordem não importasse ou fosse determinada por outros meios (por meio de um predicado ou descritor de classificação). Core Data, por exemplo, usa conjuntos quando objetos gerenciados são acessados ​​por meio de um relacionamento para muitos

iDevAmit
fonte
1

Apenas para adicionar um pouco, eu uso set às vezes apenas para remover duplicatas da matriz como: -

NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
tryKuldeepTanwar
fonte