What is the Javascript Set object for?

Asked

Viewed 623 times

9

I’ve asked a similar question about the Python language: What’s the set for in Python?.

I wonder if that object Setin Javascript does the same things as set python makes.

Example:

var numbers = new Set([1, 2, 3])

numbers.forEach(function (i) {
  console.log(i);
})

  • What is the purpose of Set?
  • Which browsers support it? Currently (2018), it is supported on all?
  • If you don’t have support in all browsers, there is some Polyfill?

Issue 1

  • What values can I add to an object Set?
  • I can have a string and int collection on the same object Set?
  • What is the criterion for determining whether an element already belongs to the object Set?
  • @Andersoncarloswoss has carte blanche to edit :p

3 answers

7


The Set is a object that allows setar unique values.

You can start a Set empty, or start already with some content from the constructor:

let foo = new Set([1, 2, 3, 4, 5]);
foo.add(6);
console.log(foo.entries());

Will return:

SetIterator {1, 2, 3, 4, 5, 6}

Iterating a Set

The .entries can be used in a for to iterate, just as you can use the method .forEach of the own Set, thus:

//O primeiro e o segundo argumento tem o mesmo valor
//o terceiro retorna o Set atual, pode ser interessante se usar a função para diferentes Sets
foo.forEach(function (valor1, valor2, currentSet) {
    console.log('set[' + chave + '] = ' + valor);

    console.log(currentSet); //Exibe o Set atual
});

Note that the forEach has a second argument:

.forEach(callback [, thisArg])

In place of thisArg you can put something else so that the this inside the callback is what you defined, as being the this of the above scope, example:

let foo = new Set([1, 2, 3, 4, 5]);

document.querySelector("#test").onclick = function () {
    foo.forEach(function (v1, v2, thisArg) {
        console.log(v1, v2, this);
    }, this);
};
<button id="test">Testar</button>

Another way to iterate is to use your own Set directly within a for...of (or for...in, although this second has no advantage, since we only care about the value):

for (let valor of foo) {
     console.log(valor);
}

I believe that this way is even cleaner than using .entries or .forEach, the advantage of .forEach even would be the use of callbacks dynamics, so instead of writing three lines like this:

for (let valor of foo) {
     meuCallback(valor);
}

You would write only one like this:

foo.forEach(meuCallback);

Then you can use for...of when it’s just iterate and forEach when you have dynamic callbacks.


Support for the Set

According to the MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/forEach

The browsers that support are:

  • Chrome 38+
  • Edge 12+
  • IE 11+ (miraculously, I didn’t expect this)
  • Safari 8+
  • Firefox 25+

If you don’t have support in all browsers, there is some Polyfill?

I’ll be honest, and take this as a personal opinion, Polyfill for this seems a bit of an exaggeration, it’s serious, as the intention is to create single values a simple check with Array.indexOf would already resolve before adding to an Array something, for example:

var x = [1,2,3];

//Supondo que este if seja executado por um callback e que os dados sejam dinamicos
var novo = 3;

if (x.indexOf(novo) === -1) {
    x.push(novo);
} else {
    console.log('Já adicionado');
}

But if you think you’re gonna use this on a lot of things, maybe a polyfill is useful. Once you test the polyfills mentioned in the comments and make sure they work well I will add here (I don’t usually add something that I haven’t tested at least once).


Converting to Array or Arguments

To convert to array you can use the three dots (this is called Spread syntax and this nay is supported in Internet Explorer), thus:

let foo = new Set([1, 2, 3, 4, 5]);

let arr = [...foo];

console.log(arr);

Or you can pass to arguments of a function like this

let foo = new Set([1, 2, 3, 4, 5]);

teste1(...foo);
teste2(...foo);

//Especificos
function teste1(a, b, c, d) {
    console.log("test1:", a, b, c, d);
}

//usando "arguments"
function teste2() {
    console.log("test2:", arguments);
}

Support for the Spread:

  • Chrome 46+
  • Edge 12+
  • Firefox 16+
  • Safari 8+

Another way is by using the Array.from:

Array.from(foo);

Support:

  • Chrome 45+
  • Edge (apparently all versions)
  • Firefox 32+
  • Safari 9+

Details about the Set

What values can I add to a Set object?

Anything even that could add to a variable or array, it works as an array itself, but simply has the detail of the control of single values

I can have a string and int collection in the same Set object?

Yeah, can stand anything, can even have Set inside Set, but one thing needs to be clear, the added values of Objects are like references, ie the value is not copied it is referenced, this in Arrays and Object too, because this is how Javascript is, of course you can copy/clone an entire object, but this is another story.

What is the criterion for determining whether an element already belongs to the Set object?

You can use the .has, it is worth noting that it is as said, it is all as reference, so for example:

var a = {};
var b = {};

console.log(a === b); //Retorna FALSE

Although similar are different objects, so in doing this:

var a = {};
var meuSet = new Set;

meuSet.add(a);

console.log(meuSet.has({})); //Retorna FALSE
console.log(meuSet.has(a)); //Retorna TRUE

The meuSet.has(a) returns TRUE because it checks the object itself referenced in the variable a, This has nothing to do with the Set, but yes how Javascript works (such behavior is similar in many languages)

  • 1

    Cool, the answer has some important details and features to consider. + 1

4

It basically creates a collection of unique objects. It is new to ES6, so it is not yet compatible with all browsers. Below is a compatibility link.

Unlike a common collection or dictionary, you do not retrieve an object directly by a key, the object is already a key, which must be unique. You can tell by the way we add values:

var colecao = new Set();
colecao.add(1);
colecao.add("teste");

Note that it can be added by adding any type of object. It has methods like has to know if an item already exists in the collection, but to recover the objects, one must iterate, here in example:

colecao.forEach(function(valor) {
  console.log(valor);
});

It seems to me an object with a function similar to "I will add items that I want to mark, as executed or existing, and then check if they are in the collection", since you can’t directly obtain an object from the collection.

Here more information and also at the end a browser compatibility Chart: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

Updated here on 12/07/2018:

Chrome  Edge    Firefox Internet Explorer   Opera   Safari
38      12      13      11                  25      8

Ah, I don’t know any Polyfill to circumvent the compatibility problem.

EDIT: to answer the new questions:

What values can I add to a Set object?
Any type of object.

I can have a string and int collection in the same Set object?
Yes, even in the example above demonstrates this.

What is the criterion for determining whether an element already belongs to the Set object?
Good question, probably some kind of hash, just guess here.

  • Would Polyfill implement from scratch? Doesn’t it seem complicated to do

  • @Jeffersonquesado was going to talk now. I’m thinking of doing a :p

  • It doesn’t seem to be very difficult even @Jeffersonquesado, a prototype to extend and be very transparent and keep adding items in an array, gives up a code to put in the github :P

  • Already have @Ricardopunctual. Take a look at link

  • Damn holy Bible speed, no time to even think.. :)

  • @Ricardopunctual Ué? this time you arrived late. They implemented it before you. Tum dum tss!

  • I was thinking about the functionality of this, and I remembered that once I had to process a text file that some information repeats in alternate lines, and just need to use the first one, then basically to control I created a list and added the key of this line and see if it already existed. This object would fall like a glove for this

  • The idea is not need to check to add if you have or not. This is great for me.

  • 1

    @Wallacemaxters but put late on that, the last commit was in 2014!!!

Show 4 more comments

4

Ministry of Health warns: this response has high concentrations of theory

Set

The object Set is defined in Ecmascript 2015 as a keyed colletion, along with three other objects: Map, WeakMap and WeakSet, as a collection of values of the Ecmascript language, where different values occur only once as an element of the set - different values are broken down using the comparison algorithm SameValueZero.

Sets must be implemented using tables hash or other arrangements which, on average, provide access time that is sublinear to the number of items in the pool. Any feature commented on in this response will be in relation to the implementation specification provided by Ecmascript and may not accurately represent the model implemented by browsers.

Are considered as values of the Ecmascript language the guys Undefined, Null, Boolean, String, Symbol, Number and Object

Constructor Set

The Set is the intrinsic object %Set% and also the initial value of the global property Set. When called as a constructor, it creates and initializes a new set, but even though it is callable, Set cannot be called as function, triggering an exception when done: Uncaught Typeerror: Constructor Set requires 'new'.

const s1 = new Set();  // Ok
const s2 = Set();  // Exception

The builder Set is designed to be inherited by other classes. Classes that inherit from Set and want to maintain the behavior of this should call super at its initialization so that the new set is effectively created and initialized in the state necessary to support the entire structure foreseen in Set.prototype.

class Numbers extends Set {
  constructor (numbers) {
    super(numbers)
  }
}


const n = new Numbers([1, 2, 3]);

console.log(...n);

Initialization of a Set

Set ( [ iterable ] )

When the builder Set is called with an optional parameter iterable the following steps are executed:

  1. If newTarget for undefined, raises the exception TypeError;
  2. Defines set as OrdinaryCreateFromConstructor(NewTarget, "%SetPrototype%", «‍[[SetData]]» );
  3. If set for a abrupt conclusion, return;
  4. Sets the internal slot [[SetData]] of set as a new empty list (List);
  5. If iterable not present, defines it as undefined;
  6. If iterable for undefined or null, defines it as undefined;
  7. Otherwise:
    • Defines adder as Get(set, "add");
    • If adder for a abrupt conclusion, return;
    • If adder is not callable, throws an exception TypeError;
    • Defines iter as GetIterator(iterable);
    • If iter for a abrupt conclusion, return;
  8. If iter for undefined, return set;
  9. Repeat:
    • Defines next as IteratorStep(iter);
    • If next for a abrupt conclusion, return;
    • If next for false, return set;
    • Defines nextValue as IteratorValue(next);
    • If nextValue for a abrupt conclusion, return;
    • Defines status as Call(adder, set, «nextValue.[[value]]»);
    • If status for a abrupt conclusion, return IteratorClose(iter, status);

Notice that the initialization itself calls the method add to add the input values, then to better understand, it will be necessary to also analyze this method.

Adding values

Set.prototype.add ( value )

When the method add set is called, the following steps are executed:

  1. Defines S as the object this;
  2. If Type(S) is not Object throws an exception TypeError;
  3. If S do not have an internal slot [[SetData]], throws an exception TypeError;
  4. Defines entries like the list that is the value of the internal slot [[SetData]];
  5. Repeat for each e that belongs to entries:
    • If e is not empty and SameValueZero(e, value) return true, Return S;
  6. If value for -0, defines it as +0;
  7. Adds value as the last value of entries;
  8. Return S;

A rather simple algorithm, however, not trivial given the dependency that there is with the return of SameValueZero. This SameValueZero is a comparison algorithm implemented in Ecmascript and we need to understand it as well.

Comparison SameValueZero

SameValueZero(x, y)

SameValueZero is a comparison algorithm implemented in Ecmascript that follows the following steps:

  1. If x for a abrupt conclusion, return;
  2. If y for a abrupt conclusion, return;
  3. If Type(x) is different from Type(y), return false;
  4. If Type(x) is Undefined, return true;
  5. If Type(x) is Null, return true;
  6. If Type(x) is Number, then:
    • If x is NaN and y is NaN, return true;
    • If x is -0 and y is +0, return true;
    • If x is +0 and y is -0, return true;
    • If x has the same numerical value as y, return true;
    • If you don’t return false;
      1. If Type(x) is String, then:
    • If x and y are exactly the same sequence of code units (same length and same code units in the respective indexes), return true;
    • If not, come back false;
      1. If Type(x) is Boolean, then:
    • If x and y are both true or both false, return true;
    • If not, come back false;
      1. If Type(x) is Symbol, then:
    • If x and y are the same symbol value, return true;
    • If not, come back false;
      1. Return true of x and y are the same object, but return false;

Note: important to note that even NaN being different from NaN, within the algorithm SameValueZero, if both entries are numerical and equal to NaN, the return will be true.

Questions

Given the brief introduction of Set, let’s go to the questions:

What is the purpose of the Set?

It serves to represent a collection of non-uniform and unique values. Uniqueness is given by the very definition of sets in mathematics, which states that if given two sets A and B, such that A is contained in B and B is contained in A, then A = B, where it is said that A is contained in B if for every element belonging to A also belongs to B.

inserir a descrição da imagem aqui

As described in the introduction, the implementation of the set is usually done through a table hash, that has a 1:1 relationship between the key and value, which, in some languages, makes the order of the elements within the set not guaranteed, but that the access time is, on average, independent of the amount of elements.

How can the search for an element in a set be O(1)? (talks about it in Python)

I found nothing official regarding the implementation of Set in Javascript, but I would say you can use the Set when you need a collection of unique items, not depending on their order and that access to them is quick.

Which browsers support it? Currently (2018), it is supported on all?

If you don’t have support in all browsers, there is some Polyfill?

See other answers.

What values can I add to a Set object?

All intended as Ecmascript language types: Undefined, Null, Boolean, String, Symbol, Number and Object.

I can have a string and int collection in the same Set object?

Can, type will be considered within the algorithm SameValueZero which, if of different types, are already considered as different objects.

What is the criterion for determining whether an element already belongs to the Set object?

It may vary depending on the implementation, but I believe everyone should satisfy the algorithm SameValueZero described above. Many languages use mechanisms of hash of the input value as the set key itself, simply calculate the hash of the input object and checking if it exists in the current table.

  • 1

    Answer with Disclaimer from the Ministry of Health? Hahaha, good

  • 1

    I think a little Latex in the set theory part would help in reading.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.