DEV Community

Cover image for JavaScript: Set vs Array, quando e como usar?
Eduardo Rabelo
Eduardo Rabelo

Posted on

JavaScript: Set vs Array, quando e como usar?

O que é Set e o que é Array?

Todos que trabalham com JS até agora estão familiarizados com o Array (não me diga que não!). Mas o que exatamente é um Array?
Bem, em geral, Array é um tipo de estrutura que representa um bloco de dados (números, objetos, etc…) alocados em memória de modo consecutivo.

Por exemplo, [1, 2, 3, 2]

E o que é Set?

Set, um conceito mais familiar da matemática, é um tipo de dados abstrato que contém apenas elementos/objetos distintos, sem a necessidade de ser alocado por ordem por índice.

Por exemplo, {1, 2, 3}

Sim, por definição, Array e Set são conceitos tecnicamente diferentes.

Uma das maiores diferenças aqui, você pode perceber, é que os elementos no Array podem ser duplicados (a menos que você diga que não deve ser), e no Set, eles simplesmente não podem ser (independentemente do que você decidir).

Além disso, Array é considerado como tipo de estrutura de dados chamada de "coleção indexada" (indexed collection), enquanto Set é considerado como "coleção com chaves" (keyed collection).

Um lembrete rápido para quem não se lembra:

  • Coleções indexadas são coleções de dados que são ordenadas por um valor de índice
  • Coleções com chaves são coleções que usam chaves, estes contêm elementos que são iteráveis na ordem de inserção.

Agora ficou fácil, certo? Podemos nos perguntar: "...se são diferentes, por que nos incomodamos em comparar um com o outro?"

No mundo da programação, com o mesmo conjunto de dados (sem duplicatas), podemos usar Array ou Set para ser nossa estrutura escolhida para armazenar esse conjunto de dados. No entanto, dependendo do caso de uso, a escolha da estrutura correta contribui para fornecer a solução ideal - e queremos alcançar isso. Para entender qual escolher, precisamos entender primeiro quem são, como são construídos e do que são capazes cada uma dessas estruturas. Aprendemos com "quem são", vamos passar para "como inicializar um" em JS.

Inicilizando

Array

Array é muito direto. Para declarar um novo array no JS, você pode usar a forma literal diretamente:

var arr = []; // array vazio 
var arr = [1,2,3]; // array que contém 1,2,3

Ou use o construtor embutido:

var arr = new Array(); // array vazio 
var arr = new Array(1,2,3); // array que contém 1,2,3

Ou ainda mais legal:

var arr = Array.from ("123"); // ["1", "2", "3"]

Apenas um conselho - não use new Array () a menos que você realmente precise, já que:

  • ele executa muito mais lento que o literal [] (isso será explicado em um artigo diferente - talvez;)).
  • [] economiza mais tempo de digitação (experimente :))
  • você pode acabar cometendo alguns erros clássicos , como:
var arr1 = new Array(10); // arr1[0] = undefined, mas arr1.length = 10
var arr2 = [10]; // arr2[0] = 10 e arr2.length = 1;
var arr3 = new Array(1,2,3); // [1,2,3]
var arr4 = [1,2,3]; // [1,2,3] 

Então, regra geral Nº1 - mantenha a simplicidade!

Set

Set tem um construtor embutido. Sim, não há nenhum atalho como em arrays.

Set([iterável])

Para criar um novo conjunto, precisamos usar uma nova sintaxe, por exemplo:

var emptySet = new Set(); 
var exampleSet = new Set([1,2,3]);

Mas definitivamente não:

new Set(1);

Set recebe o objeto iterável como seu parâmetro de entrada e criará o objeto Set respectivamente. Portanto, podemos construir um conjunto a partir de um array - mas ele só incluirá elementos distintos desse array/não duplicados.

E, claro, também podemos converter um Set de volta para array usando o método Array.from().

var set = new Set([1,2,3]); // {1,2,3}
var arr = Array.from(set); // [1,2,3]

OK, agora que sabemos como criá-los, e as suas capacidades? Vamos fazer uma pequena comparação entre os métodos mais básicos fornecidos pelo Array e Set, que são:

Localizando e acessando um elemento

  • Primeiro de tudo, Set não suporta acesso aleatório a um elemento por índice como em Array, o que significa:
console.log(set[0]); //undefined
console.log(arr[0]); //1
  • Mais importante, porque os dados do array são armazenados na memória consecutivamente, a CPU poderá acessar os dados muito mais rápido devido à pré-busca. Portanto, em geral, acessar um elemento no array (um após o outro, como em um loop for) é mais rápido e mais eficiente se comparado com outros tipos de dados abstratos.
  • Verificar se um elemento existe em um Set tem uma sintaxe mais simples do que em um Array, usando Set.prototype.has(value) vs Array.prototype.indexOf(value).
console.log(set.has(0)); // false
console.log(arr.indexOf(0)); // -1

console.log(set.has(1)); // true
console.log(arr.indexOf(1)); //0

O que significa que em Array, precisamos fazer uma verificação extra se queremos fazer uma condição em que o elemento está em Array:

var isExist = arr.indexOf (1)! == -1;

O ES6 fornece Array.prototype.includes() que se comporta de forma semelhante ao .has(), no entanto, não é suportado em todos os navegadores, ou em outras palavras, no IE (surpresa :)!).

Adicionando/Inserindo novo elemento

  • Adicionar um novo elemento ao Array pode ser feito rapidamente em O(1) usando Array.prototype.push() - o elemento será adicionado ao final do array.
arr.push(4); //[1,2,3,4]
  • Ou também pode ser feito em O(n) usando Array.prototype.unshift() - adicionando o elemento ao início do array, onde n é o comprimento do array atual.
arr.unshift(3); // [3,1,2,3]
arr.unshift(5, 6); // [5,6,3,1,2,3]
  • Em Set, há apenas uma maneira de adicionar novo elemento, Set.prototype.add(). Como Set precisa manter as propriedades "distintas" entre os membros do conjunto, em cada vez que usamos .add(), o Set precisa verificar todos os membros antes de continuar, para garantir que não haja duplicados. Geralmente add() terá O(n) em tempo de execução. No entanto, graças à abordagem de implementação da tabela de hash (hash table), add() em Set provavelmente será apenas O(1).
set.add(3); // {1,2,3} 
set.add(4); // {1,2,3,4}

Aprendemos que na adição de elementos, Set executa quase que as mesmas operações que Array. E como fica a remoção?

Removendo elemento

  • Uma das coisas boas que tornam o Array tão popular é porque ele fornece muitos métodos diferentes para remover um elemento, por exemplo:

.pop() - remove e retorna o último elemento. Isso leva O(1).

var arr = [5,6,1,2,3,4]
arr.pop (); // retorna 4

.shift() - remove e retorna o primeiro elemento. Isso leva O(n).

var arr = [5,6,1,2,3,4]
arr.shift (); // retorna 5

.splice(index, deleteCount) - remove um número de elementos (deleteCount) a partir do índice (index). Isso pode levar até O(n).

var arr = [5,6,1,2,3,4]
arr.splice (0, 3); // retorna [5,6,1]

Enquanto isso, em Set, vamos usar:

.delete(element) - remove um determinado elemento específico do Set.

var set = new Set([1,2,3,4])
set.delete(4); // retorna `true`, agora "set" é {1,2,3}

.clear() - remove todos os elementos do Set.

var set = new Set([1,2,3,4])
set.clear(); // retorna `undefined`, agora "set" é {}
  • Enquanto o Array não suporta um método nativo para remover um dado elemento específico (exceto se conhecermos o seu índice), precisaremos da ajuda de uma função externa extra para procurar pelo índice desse elemento e executar o .splice(), já o Set tem .delete(element) - simples e fácil de usar.

Além disso, o Array nos fornece muito mais funcionalidades nativas (.reduce(), .reverse(), .sort(), etc…), comparado ao Set, que atualmente possui apenas as funcionalidades mais básicas mencionadas acima. Então, alguns de vocês podem pensar, por que preferiríamos Set ao invés de Array?

Então, qual é melhor? E quando é melhor utilziar Array?

  • Em primeiro lugar, Set é diferente de Array. Não se destina a substituir totalmente o Array, mas fornecer um tipo de suporte adicional para concluir o que falta no Array.
  • Como o Set contém apenas elementos distintos, deixa a vida muito mais fácil se soubermos antecipadamente que queremos evitar salvar dados duplicados em nossa estrutura.
  • Operações básicas de Set como union(), intersect(), difference(), etc ... são facilmente implementadas de forma eficaz com base nas operações internas nativas fornecidas. Devido ao método delete(), fazer intersect/union entre 2 Sets é muito mais confortável do que fazer o mesmo com 2 Arrays.
  • Array destina-se a cenários em que queremos manter elementos ordenados para acesso rápido ou fazer modificações pesadas (remover e adicionar elementos) ou qualquer ação necessária para acesso direto ao índice de elementos (por exemplo, tente fazer Pesquisa Binária em Sets ao invés de Arrays - como você acessa o elemento localizado no meio?)

Conclusão

Em geral, na minha opinião, Set realmente não tem uma grande vantagem sobre o Array, exceto em cenários específicos, como quando queremos manter dados distintos/não duplicados com o mínimo de esforço, ou trabalhar com vários conjuntos de dados distintos juntos usando as operações mais básicas do Set, sem a necessidade de acessar elementos diretamente.

Caso contrário, Array sempre! Por qual razão? Menos trabalho para CPU em buscar o elemento quando for necessário.

Você concorda? Sinta-se livre para discutir ;).

Créditos

Top comments (1)

Collapse
 
davidcostadev profile image
David Costa • Edited

Não conhecia porque existia o set. Ótima explicação.