820

Set seems like a nice way to create Arrays with guaranteed unique elements, but it does not expose any good way to get properties, except for generator [Set].values, which is called in an awkward way of mySet.values.next().

This would have been ok, if you could call map and similar functions on Sets. But you cannot do that, as well.

I've tried Array.from, but seems to be converting only array-like (NodeList and TypedArrays ?) objects to Array. Another try: Object.keys does not work for Sets, and Set.prototype does not have similar static method.

So, the question: Is there any convenient inbuilt method for creating an Array with values of a given Set ? (Order of element does not really matter).

if no such option exists, then maybe there is a nice idiomatic one-liner for doing that ? like, using for...of, or similar ?

c69
  • 19,951
  • 7
  • 52
  • 82

10 Answers10

1416

if no such option exists, then maybe there is a nice idiomatic one-liner for doing that ? like, using for...of, or similar ?

Indeed, there are several ways to convert a Set to an Array:

Note: safer for TypeScript.

const array = Array.from(mySet);

Note: Spreading a Set has issues when compiled with TypeScript (See issue #8856). It's safer to use Array.from above instead.

const array = [...mySet];
  • The old-fashioned way, iterating and pushing to a new array (Sets do have forEach):
const array = [];
mySet.forEach(v => array.push(v));
  • Previously, using the non-standard, and now deprecated array comprehension syntax:
const array = [v for (v of mySet)];
Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • 2
    `var array = [v for (v of mySet)];` does not work in [tag:Chrome] 46 – Eric Oct 27 '15 at 21:36
  • 1
    looks like chrome supports as of 45 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#AutoCompatibilityTable – amwinter Dec 11 '15 at 23:00
  • Also, the last one is using this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Array_comprehensions, which is a non-standard and deprecated feature – Alex Aug 14 '18 at 16:35
  • which way is better? – Vic Jan 24 '19 at 18:28
  • 22
    Just wanted to add that `[...mySet]` has issues when compiled using Typescript (see [this issue](https://github.com/Microsoft/TypeScript/issues/8856)), so probably safer to use `Array.from(mySet)` if you intend to convert to Typescript in the near future. – Ivan Gozali Mar 11 '19 at 16:24
  • Spread operator returns a [Set(3)] instead of ['a','b','c'] only on production, on dev environment it looks ok, any idea why? Maybe something because uglification or something other in webpack? Array.from() solves this issue. – Pumych May 26 '21 at 15:18
  • 5
    By the way, if anyone is concerned about speed, here's a ranking from fastest to slowest: #1. old-fashioned (forEach/for of); #2. Array.from (~5% slower); #3. spreading (~12% slower) – Cezar D. Aug 16 '21 at 09:49
  • @Pumych If you use babel to transpile your code, https://stackoverflow.com/questions/71021389/babel-incorrect-transformation-of-spread/71021566 and https://github.com/jaredpalmer/tsdx/issues/376#issuecomment-566750042 may help you. – Feng Yu Feb 11 '22 at 15:39
  • Wow, I never knew that array comprehension was ever a thing in JavaScript. – tczx3 Aug 30 '22 at 16:20
98

via https://speakerdeck.com/anguscroll/es6-uncensored by Angus Croll

It turns out, we can use spread operator:

var myArr = [...mySet];

Or, alternatively, use Array.from:

var myArr = Array.from(mySet);
c69
  • 19,951
  • 7
  • 52
  • 82
  • 3
    refer to https://kangax.github.io/compat-table/es6/ for more or less up-to-date support chart. Currently, of all desktop browsers, only FF and IE TP (aka Spartan, aka MS Non-IE browser) support `Array.from` and `...` – c69 Mar 19 '15 at 23:58
  • Looks like Firefox is the only browser to support `Array.from`. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from – 425nesp Apr 02 '15 at 05:27
  • 1
    Here you can enable it for Chrome `chrome://flags/#enable-javascript-harmony` Remember it's experimental don't think for moment that this is a good solution for development. – sospedra Jun 15 '15 at 11:11
  • If my set is of objects, does using the `spread` syntax clone the set, or does it keep the object references? (I want to call methods in these objects so I need them to be the same, not clones) – Juan Perez Jul 18 '23 at 22:06
18

Assuming you are just using Set temporarily to get unique values in an array and then converting back to an Array, try using this:

_.uniq([])

This relies on using underscore or lo-dash.

Eric
  • 6,563
  • 5
  • 42
  • 66
aaronmgdr
  • 598
  • 4
  • 12
11

Perhaps to late to the party, but you could just do the following:

const set = new Set(['a', 'b']);
const values = set.values();
const array = Array.from(values);

This should work without problems in browsers that have support for ES6 or if you have a shim that correctly polyfills the above functionality.

Edit: Today you can just use what @c69 suggests:

const set = new Set(['a', 'b']);
const array = [...set]; // or Array.from(set)
Roland
  • 9,321
  • 17
  • 79
  • 135
  • 1
    It seems that using the `set.entries()` you will get array of pairs. You can use `set.values()` to get the plain array. – Shimon Rachlenko Jan 13 '16 at 13:14
  • @ShimonRachlenko true, and the user did ask for that. – Roland Jan 13 '16 at 16:01
  • 5
    You can just use `var array = Array.from(set);` – Buffalo May 04 '17 at 06:36
  • this answer is just wrong. You don't need the call to `.entries`, nor `.values`. As @Buffalo mentioned above - `Array.from(set)` is enough. – c69 Oct 23 '18 at 02:12
  • 1
    @c69 that is true. At the time of this answer, `Array.from()` did not work as expected. But now spread and `Array.from()` both work just fine. – Roland Oct 23 '18 at 09:50
1

The code below creates a set from an array and then, using the ... operator.

var arr=[1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,];
var set=new Set(arr);
let setarr=[...set];
console.log(setarr);
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • 2
    ..and this is what? – ZF007 Dec 31 '19 at 11:20
  • This is called [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax), which is actually 2 different operations (1) within objects (2) arrays / function argument lists. The latter follows "iteration protocols": it calls the [Symbol.iterator method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/@@iterator), then does the whole next() dance. P.S. `...` also appears in 2 similar [destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) syntaxes. – Beni Cherniavsky-Paskin Jun 30 '23 at 08:15
0

In my case the solution was:

var testSet = new Set();
var testArray = [];

testSet.add("1");
testSet.add("2");
testSet.add("2"); // duplicate item
testSet.add("3");

var someFunction = function (value1, value2, setItself) {
    testArray.push(value1);
};

testSet.forEach(someFunction);

console.log("testArray: " + testArray);

value1 equals value2 => The value contained in the the current position in the Set. The same value is passed for both arguments

Worked under IE11.

d0wn
  • 121
  • 4
0

Using Set and converting it to an array is very similar to copying an Array...

So you can use the same methods for copying an array which is very easy in ES6

For example, you can use ...

Imagine you have this Set below:

const a = new Set(["Alireza", "Dezfoolian", "is", "a", "developer"]);

You can simply convert it using:

const b = [...a];

and the result is:

["Alireza", "Dezfoolian", "is", "a", "developer"]

An array and now you can use all methods that you can use for an array...

Other common ways of doing it:

const b = Array.from(a);

or using loops like:

const b = [];
a.forEach(v => b.push(v));
Alireza
  • 100,211
  • 27
  • 269
  • 172
-1

Here is an easy way to get only unique raw values from array. If you convert the array to Set and after this, do the conversion from Set to array. This conversion works only for raw values, for objects in the array it is not valid. Try it by yourself.

    let myObj1 = {
        name: "Dany",
        age: 35,
        address: "str. My street N5"
    }

    let myObj2 = {
        name: "Dany",
        age: 35,
        address: "str. My street N5"
    }

    var myArray = [55, 44, 65, myObj1, 44, myObj2, 15, 25, 65, 30];
    console.log(myArray);

    var mySet = new Set(myArray);
    console.log(mySet);

    console.log(mySet.size === myArray.length);// !! The size differs because Set has only unique items

    let uniqueArray = [...mySet];
    console.log(uniqueArray); 
    // Here you will see your new array have only unique elements with raw 
    // values. The objects are not filtered as unique values by Set.
    // Try it by yourself.
zdrsoft
  • 2,417
  • 19
  • 10
-1

I would prefer to start with removing duplications from an array and then try to sort. Return the 1st element from new array.

    function processData(myArray) {
        var s = new Set(myArray);
        var arr = [...s];
        return arr.sort((a,b) => b-a)[1];
    }
    
    console.log(processData([2,3,6,6,5]);
-2

function countUniqueValues(arr) {
  return Array.from(new Set(arr)).length 

}

console.log(countUniqueValues([1, 2, 3, 4, 4, 4, 7, 7, 12, 12, 13]))
  • 1
    The question explicitly asks for an array, not a length. But the method covered here to convert the Set is already covered in the other answers. Not sure what this answer really adds. – General Grievance Jun 14 '22 at 00:05