10

I need to find the number of unique elements in an array.

var myArray = [ 10, 10, 20, 20, 30, 30, 40, 40, 40, 40, 50, 50, 50, 50, 60 ];

I want count = 6 (number of unique elements in array)

And, is there a way to do this without iterating through the array? (I assume that would be the fastest way?).

ANSWER: I used the .filter method as shown below. My actual array element is much more complex. I ended up iterating through my array and created a new array. Each element in the new array was a .substr of the old element. Then, the .filter method below worked great. THANKS to everyone!!

hypermiler
  • 1,969
  • 4
  • 19
  • 27

5 Answers5

13

ES6 offers a single line solution:

new Set(myArray).size
Yukulélé
  • 15,644
  • 10
  • 70
  • 94
Postlagerkarte
  • 6,600
  • 5
  • 33
  • 52
12

You need to keep a set of known values, and an auxilliary count. You can use .reduce():

var count = myArray.reduce(function(values, v) {
  if (!values.set[v]) {
    values.set[v] = 1;
    values.count++;
  }
  return values;
}, { set: {}, count: 0 }).count;

Starting with an empty set of values and a count of zero, this looks at each element to see whether it's been added to the set. If it hasn't, it's added, and the count is incremented.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • so, in this case it returns count = 6 ? Is it the fastest way? – hypermiler Feb 09 '14 at 16:39
  • 1
    I set up a performance test between your method of reducing vs a vanilla *Object set*: http://jsperf.com/js-set-test – Mr. Polywhirl Feb 09 '14 at 16:50
  • @Mr.Polywhirl For me the "reduce" is faster, but I suspect a big part of that is that the "simple" code is (correctly!) making a `hasOwnProperty` test. Otherwise the two approaches are almost exactly the same, if implemented slightly differently. – Pointy Feb 09 '14 at 18:25
4

How about filter and length:

var len = myArray.filter(function(val, i, arr) { 
    return arr.indexOf(val) === i;
}).length;
David Hellsing
  • 106,495
  • 44
  • 176
  • 212
  • hmmmm. so. what variable? is equal to 6 here? – hypermiler Feb 09 '14 at 16:37
  • 1
    I'm favoring your method for the simple reason that it necessitates less code. Two questions though. 1. is it as fast as the above two methods? and 2. I need some help understanding what (val, i, arr) mean. So, in my case, I need to find the "count" of a substring of an element in the array. So in this case for example, I need to find the number of unique occurrances of myArray.substr(3,6). I'm not sure how this maps to (val, i, arr)... thanks! – hypermiler Feb 09 '14 at 19:01
  • @hypermiler https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter – David Hellsing Feb 09 '14 at 19:41
  • @hypermiler this is simpler, but for long arrays it's going to be expensive. The `.indexOf` operation has to perform a linear search, so the execution time tends to be proportional to the *square* of the length of the array (particularly when there are not many duplicates). – Pointy Feb 09 '14 at 22:19
  • this is a very short array. Maybe max 30 elements. Usually much less. And the likelihood of duplicates is low. – hypermiler Feb 09 '14 at 22:25
  • @David. I really feel bad, this is way above my head. Sorry. I went to mozilla. Still can't get it. I tried to ask another question and was roundly chastised. Deleted the question. – hypermiler Feb 09 '14 at 23:34
1

If you happen to be using lodash:

_.uniq(myArray).length
Dean
  • 731
  • 8
  • 21
0

You can now convert your array into a unique Array and compare lengths. Do this by changing it into Set and then back to an Array. If the Set is smaller then duplicates were removed and your original Array did not contain unique values.

const isUnique = (myArray.length === [...new Set(myArray)].length);

test:

const myArray=[1,2,2,3,4]; 
console.log(myArray.length === [...new Set(myArray)].length);
false

const myArray=[1,2,3,4]; 
console.log(myArray.length === [...new Set(myArray)].length);
true
Aidan
  • 101
  • 3