192

MSDN references JavaScript's Set collection abstraction. I've got an array of objects that I'd like to convert to a set so that I am able to remove (.delete()) various elements by name:

var array = [
    {name: "malcom", dogType: "four-legged"},
    {name: "peabody", dogType: "three-legged"},
    {name: "pablo", dogType: "two-legged"}
];

How do I convert this array to a set? More specifically, is it possible to do this without iterating over the above array? The documentation is relatively lacking (sufficient for instantiated sets; not for conversions - if possible).

I may also be thinking of the conversion to a Map, for removal by key. What I am trying to accomplish is an iterable collection that can be accessed or modified via accessing the elements primarily via a key (as opposed to index).

Conversion from an array to the other being the ultimate goal.

Thomas
  • 4,827
  • 5
  • 28
  • 60
  • 1
    sounds like a plain old Object will work for you... – dandavis Mar 10 '15 at 13:32
  • can't you achieve the same by using a regular object and deleting the properties ? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete – Veverke Mar 10 '15 at 13:34
  • @Veverke not looking to delete the properties. Looking to remove the objects, themselves. – Thomas Mar 10 '15 at 13:37
  • 3
    @Thomas: so I am missing something, which I want to learn. What is the difference between var s = new Set(), adding objects and issuing s.delete(whatever) - and var o = {1: 'aaa', 2: 'bbbb' ... } and issuing delete(o['1']) ? – Veverke Mar 10 '15 at 13:39
  • 1
    @Veverke that was more descriptive than you initial comment (+1). Thank you. But, again, is it possible to do that without iterating over the array for addition of the contents of the array to the object and to retain a list like, key-accessible structure? Sounds like you've got an idea. I wouldn't mind seeing it in an answer format if you've got the time to elaborate. – Thomas Mar 10 '15 at 13:41
  • @Thomas: I am having trouble understanding "... for addition of the contents of the array to the object... " . Could you give an example scenario of what you want to accomplish - and point out what you are assuming will not work ? – Veverke Mar 10 '15 at 13:43
  • To be honest, the only difference between a Set object and a plain object is that the former provides a clear method in its API that removes all the object's properties - something which would require a loop in a plain object. So it's a "nice to have" feature. Other than that... anyone? – Veverke Mar 10 '15 at 13:47
  • You could save some keystrokes by adding them with a foreach; but it seems like the ECMAScript 6 definition doesn't include anything like what you're looking for. (For instance, I would have hoped "new Set(item1, item2)" would give what you're looking for.) And yeah, don't forget to make sure all your favorite browsers support Set, because it's ES6. – Katana314 Mar 10 '15 at 13:47
  • 2
    That array object isn't legal, since `{"bob", "dole"}` isn't a valid object. – Alnitak Mar 10 '15 at 13:51
  • 1
    @Veverke ES6 `Set` and `Map` are "pure" implementation of those data constructs that don't suffer the issues that an `Object` can when things are added to its prototype. – Alnitak Mar 10 '15 at 13:54
  • @Thomas so what's the significance of there being three separate objects each with variable numbers of keys? Which _exact_ values (or keys) do you want to appear in the `Set` ? – Alnitak Mar 10 '15 at 13:56
  • 1
    @Veverke Set does not support duplicate elements. – levi Mar 10 '15 at 13:56
  • 1
    @levi nor does an `Object`. – Alnitak Mar 10 '15 at 13:57
  • @levi/alnitak we're making progress though... :-) – Veverke Mar 10 '15 at 13:58
  • Of sorts - @Thomas - you still need (given your example input data) to tell us exactly what keys are supposed to appear in the `Set`. – Alnitak Mar 10 '15 at 14:02
  • @Veverke The set iterator preserves the insertion order of elements. Object does not. – levi Mar 10 '15 at 14:03
  • @levi: could you exemplify ? If I add an element with Set, it is added at the end... doing the same in a plain object, the same will not occur ? All right I have just tested it... and ONLY for properties whose names are integers a plain object will not keep the order - rather, will order them numerically... is that it ? – Veverke Mar 10 '15 at 14:05
  • @Veverke object ordering is not guaranteed. http://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order. A set is closer to an array than an object. – levi Mar 10 '15 at 14:06
  • @levi: I have just added a comment there... we are getting more precise, so I still ask: can't we say that the order is not guaranteed ONLY due cases where the properties are numeric strings ? – Veverke Mar 10 '15 at 14:12
  • 1
    @Veverke no, you can't say that. The order is _never_ guaranteed on an `Object`, although in a `Set` it's guaranteed to be in insertion order. – Alnitak Mar 10 '15 at 14:16
  • @Veverke p.s. this is actually mostly off topic for this question. – Alnitak Mar 10 '15 at 14:17
  • use a Map, not a Set, a map is for key values, a set is just a group of unique keys without values – Martijn Scheffer Feb 17 '18 at 13:20
  • That is not quite true @MartijnScheffer. Set and Map collections both have values but semantically represent different things.https://medium.com/ecmascript-2015/es6-set-map-weak-a2aeb7e2d384 – Thomas Feb 17 '18 at 13:46
  • a Set is a a group of Keys, a Map a group of keys and values, from the description of his problem i deduced that the Map is what he wants – Martijn Scheffer Feb 20 '18 at 21:39

4 Answers4

276

Just pass the array to the Set constructor. The Set constructor accepts an iterable parameter. The Array object implements the iterable protocol, so its a valid parameter.

var arr = [55, 44, 65];
var set = new Set(arr);
console.log(set.size === arr.length);
console.log(set.has(65));

See here

Frenchy
  • 9,646
  • 2
  • 9
  • 27
levi
  • 18,814
  • 17
  • 55
  • 68
  • strictly correct, although I've hesitated to add an answer myself since the OP's data is malformed and it's therefore unclear exactly what he expects – Alnitak Mar 10 '15 at 13:53
  • 11
    This does not work on IE11. It does not support this constructor. I would avoid it unless you know which browsers your users are going to use. – Eric Jan 17 '17 at 02:03
26

If you start out with:

let array = [
    {name: "malcom", dogType: "four-legged"},
    {name: "peabody", dogType: "three-legged"},
    {name: "pablo", dogType: "two-legged"}
];

And you want a set of, say, names, you would do:

let namesSet = new Set(array.map(item => item.name));
Ryan Shillington
  • 15,463
  • 10
  • 75
  • 85
7

By definition "A Set is a collection of values, where each value may occur only once." So, if your array has repeated values then only one value among the repeated values will be added to your Set.

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


var arr = [1, 2, 1];
var set = new Set(arr);
console.log(set); // {1,2}

So, do not convert to set if you have repeated values in your array.

Ashlesh Sortee
  • 191
  • 2
  • 13
3

What levi said about passing it into the constructor is correct, but you could also use an object.

I think what Veverke is trying to say is that you could easily use the delete keyword on an object to achieve the same effect.

I think you're confused by the terminology; properties are components of the object that you can use as named indices (if you want to think of it that way).

Try something like this:

var obj = {
    "bob": "dole",
    "mr.": "peabody",
    "darkwing": "duck"
};

Then, you could just do this:

delete obj["bob"];

The structure of the object would then be this:

{
    "mr.": "peabody",
    "darkwing": "duck"
}

Which has the same effect.

Community
  • 1
  • 1
AstroCB
  • 11,800
  • 20
  • 54
  • 68
  • 1
    Thanks Astro :-). Indeed, this opened up the question: "what is the difference between a Set object and a plain object" ? Although, as I have noted in the comments above, "Set" is a wrap up type that offers the "nice to have functionality" of "clear". – Veverke Mar 10 '15 at 13:59
  • In a short, I think the post's title should be changed to "What is the difference between a Set object and a plain object in javascript", and note that "In trying to achieve this this and that... I ended up asking myself what is the difference between... – Veverke Mar 10 '15 at 14:02
  • @Veverke "what is the difference between a Set object and a plain object", could just read the doc .. – Hacketo Mar 10 '15 at 14:04
  • 1
    @Hacketo: do you find any other than Set providing "Clear" in its api ? – Veverke Mar 10 '15 at 14:11
  • @Veverke `size` maybe; a plain object can have multiple same value, Set can't... just as the doc says – Hacketo Mar 10 '15 at 14:25
  • @Hacketo no, a plain object _cannot_ have more than one key with the same name. – Alnitak Mar 10 '15 at 14:28
  • @Alnitak, I'm not talking about keys, but values, a Set seem more like an array of unique values than a plain object – Hacketo Mar 10 '15 at 14:28