This question already has answers here:
Get all unique values in a JavaScript array (remove duplicates)
(91 answers)
Closed 1 year ago.
How can I get a list of unique values in an array? Do I always have to use a second array or is there something similar to java's hashmap in JavaScript?
I am going to be using JavaScript and jQuery only. No additional libraries can be used.
Here's a much cleaner solution for ES6 that I see isn't included here. It uses the Set and the spread operator: ...
var a = [1, 1, 2];
[... new Set(a)]
Which returns [1, 2]
Or for those looking for a one-liner (simple and functional) compatible with current browsers:
let a = ["1", "1", "2", "3", "3", "1"];
let unique = a.filter((item, i, ar) => ar.indexOf(item) === i);
console.log(unique);
Update 2021
I would recommend checking out Charles Clayton's answer, as of recent changes to JS there are even more concise ways to do this.
Update 18-04-2017
It appears as though 'Array.prototype.includes' now has widespread support in the latest versions of the mainline browsers (compatibility)
Update 29-07-2015:
There are plans in the works for browsers to support a standardized 'Array.prototype.includes' method, which although does not directly answer this question; is often related.
Usage:
["1", "1", "2", "3", "3", "1"].includes("2"); // true
Pollyfill (browser support, source from mozilla):
// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
Object.defineProperty(Array.prototype, 'includes', {
value: function(searchElement, fromIndex) {
// 1. Let O be ? ToObject(this value).
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If len is 0, return false.
if (len === 0) {
return false;
}
// 4. Let n be ? ToInteger(fromIndex).
// (If fromIndex is undefined, this step produces the value 0.)
var n = fromIndex | 0;
// 5. If n ≥ 0, then
// a. Let k be n.
// 6. Else n < 0,
// a. Let k be len + n.
// b. If k < 0, let k be 0.
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
// 7. Repeat, while k < len
while (k < len) {
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
// b. If SameValueZero(searchElement, elementK) is true, return true.
// c. Increase k by 1.
// NOTE: === provides the correct "SameValueZero" comparison needed here.
if (o[k] === searchElement) {
return true;
}
k++;
}
// 8. Return false
return false;
}
});
}
Since I went on about it in the comments for #Rocket's answer, I may as well provide an example that uses no libraries. This requires two new prototype functions, contains and unique
Array.prototype.contains = function(v) {
for (var i = 0; i < this.length; i++) {
if (this[i] === v) return true;
}
return false;
};
Array.prototype.unique = function() {
var arr = [];
for (var i = 0; i < this.length; i++) {
if (!arr.contains(this[i])) {
arr.push(this[i]);
}
}
return arr;
}
var duplicates = [1, 3, 4, 2, 1, 2, 3, 8];
var uniques = duplicates.unique(); // result = [1,3,4,2,8]
console.log(uniques);
For more reliability, you can replace contains with MDN's indexOf shim and check if each element's indexOf is equal to -1: documentation
One Liner, Pure JavaScript
With ES6 syntax
list = list.filter((x, i, a) => a.indexOf(x) === i)
x --> item in array
i --> index of item
a --> array reference, (in this case "list")
With ES5 syntax
list = list.filter(function (x, i, a) {
return a.indexOf(x) === i;
});
Browser Compatibility: IE9+
Using EcmaScript 2016 you can simply do it like this.
var arr = ["a", "a", "b"];
var uniqueArray = Array.from(new Set(arr)); // Unique Array ['a', 'b'];
Sets are always unique, and using Array.from() you can convert a Set to an array. For reference have a look at the documentations.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
These days, you can use ES6's Set data type to convert your array to a unique Set. Then, if you need to use array methods, you can turn it back into an Array:
var arr = ["a", "a", "b"];
var uniqueSet = new Set(arr); // {"a", "b"}
var uniqueArr = Array.from(uniqueSet); // ["a", "b"]
//Then continue to use array methods:
uniqueArr.join(", "); // "a, b"
If you want to leave the original array intact,
you need a second array to contain the uniqe elements of the first-
Most browsers have Array.prototype.filter:
const unique = array1.filter((item, index, array) => array.indexOf(item) === index);
//if you need a 'shim':
Array.prototype.filter= Array.prototype.filter || function(fun, scope){
var T= this, A= [], i= 0, itm, L= T.length;
if(typeof fun== 'function'){
while(i<L){
if(i in T){
itm= T[i];
if(fun.call(scope, itm, i, T)) A[A.length]= itm;
}
++i;
}
}
return A;
}
Array.prototype.indexOf= Array.prototype.indexOf || function(what, i){
if(!i || typeof i!= 'number') i= 0;
var L= this.length;
while(i<L){
if(this[i]=== what) return i;
++i;
}
return -1;
}
Fast, compact, no nested loops, works with any object not just strings and numbers, takes a predicate, and only 5 lines of code!!
function findUnique(arr, predicate) {
var found = {};
arr.forEach(d => {
found[predicate(d)] = d;
});
return Object.keys(found).map(key => found[key]);
}
Example: To find unique items by type:
var things = [
{ name: 'charm', type: 'quark'},
{ name: 'strange', type: 'quark'},
{ name: 'proton', type: 'boson'},
];
var result = findUnique(things, d => d.type);
// [
// { name: 'charm', type: 'quark'},
// { name: 'proton', type: 'boson'}
// ]
If you want it to find the first unique item instead of the last add a found.hasOwnPropery() check in there.
Not native in Javascript, but plenty of libraries have this method.
Underscore.js's _.uniq(array) (link) works quite well (source).
If you don't need to worry so much about older browsers, this is exactly what Sets are designed for.
The Set object lets you store unique values of any type, whether
primitive values or object references.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
const set1 = new Set([1, 2, 3, 4, 5, 1]);
// returns Set(5) {1, 2, 3, 4, 5}
Using jQuery, here's an Array unique function I made:
Array.prototype.unique = function () {
var arr = this;
return $.grep(arr, function (v, i) {
return $.inArray(v, arr) === i;
});
}
console.log([1,2,3,1,2,3].unique()); // [1,2,3]
Short and sweet solution using second array;
var axes2=[1,4,5,2,3,1,2,3,4,5,1,3,4];
var distinct_axes2=[];
for(var i=0;i<axes2.length;i++)
{
var str=axes2[i];
if(distinct_axes2.indexOf(str)==-1)
{
distinct_axes2.push(str);
}
}
console.log("distinct_axes2 : "+distinct_axes2); // distinct_axes2 : 1,4,5,2,3
Majority of the solutions above have a high run time complexity.
Here is the solution that uses reduce and can do the job in O(n) time.
Array.prototype.unique = Array.prototype.unique || function() {
var arr = [];
this.reduce(function (hash, num) {
if(typeof hash[num] === 'undefined') {
hash[num] = 1;
arr.push(num);
}
return hash;
}, {});
return arr;
}
var myArr = [3,1,2,3,3,3];
console.log(myArr.unique()); //[3,1,2];
Note:
This solution is not dependent on reduce. The idea is to create an object map and push unique ones into the array.
You only need vanilla JS to find uniques with Array.some and Array.reduce. With ES2015 syntax it's only 62 characters.
a.reduce((c, v) => b.some(w => w === v) ? c : c.concat(v)), b)
Array.some and Array.reduce are supported in IE9+ and other browsers. Just change the fat arrow functions for regular functions to support in browsers that don't support ES2015 syntax.
var a = [1,2,3];
var b = [4,5,6];
// .reduce can return a subset or superset
var uniques = a.reduce(function(c, v){
// .some stops on the first time the function returns true
return (b.some(function(w){ return w === v; }) ?
// if there's a match, return the array "c"
c :
// if there's no match, then add to the end and return the entire array
c.concat(v)}),
// the second param in .reduce is the starting variable. This is will be "c" the first time it runs.
b);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Another thought of this question. Here is what I did to achieve this with fewer code.
var distinctMap = {};
var testArray = ['John', 'John', 'Jason', 'Jason'];
for (var i = 0; i < testArray.length; i++) {
var value = testArray[i];
distinctMap[value] = '';
};
var unique_values = Object.keys(distinctMap);
console.log(unique_values);
Array.prototype.unique = function () {
var dictionary = {};
var uniqueValues = [];
for (var i = 0; i < this.length; i++) {
if (dictionary[this[i]] == undefined){
dictionary[this[i]] = i;
uniqueValues.push(this[i]);
}
}
return uniqueValues;
}
I have tried this problem in pure JS.
I have followed following steps 1. Sort the given array, 2. loop through the sorted array, 3. Verify previous value and next value with current value
// JS
var inpArr = [1, 5, 5, 4, 3, 3, 2, 2, 2,2, 100, 100, -1];
//sort the given array
inpArr.sort(function(a, b){
return a-b;
});
var finalArr = [];
//loop through the inpArr
for(var i=0; i<inpArr.length; i++){
//check previous and next value
if(inpArr[i-1]!=inpArr[i] && inpArr[i] != inpArr[i+1]){
finalArr.push(inpArr[i]);
}
}
console.log(finalArr);
Demo
You can enter array with duplicates and below method will return array with unique elements.
function getUniqueArray(array){
var uniqueArray = [];
if (array.length > 0) {
uniqueArray[0] = array[0];
}
for(var i = 0; i < array.length; i++){
var isExist = false;
for(var j = 0; j < uniqueArray.length; j++){
if(array[i] == uniqueArray[j]){
isExist = true;
break;
}
else{
isExist = false;
}
}
if(isExist == false){
uniqueArray[uniqueArray.length] = array[i];
}
}
return uniqueArray;
}
Here is an approach with customizable equals function which can be used for primitives as well as for custom objects:
Array.prototype.pushUnique = function(element, equalsPredicate = (l, r) => l == r) {
let res = !this.find(item => equalsPredicate(item, element))
if(res){
this.push(element)
}
return res
}
usage:
//with custom equals for objects
myArrayWithObjects.pushUnique(myObject, (left, right) => left.id == right.id)
//with default equals for primitives
myArrayWithPrimitives.pushUnique(somePrimitive)
I was just thinking if we can use linear search to eliminate the duplicates:
JavaScript:
function getUniqueRadios() {
var x=document.getElementById("QnA");
var ansArray = new Array();
var prev;
for (var i=0;i<x.length;i++)
{
// Check for unique radio button group
if (x.elements[i].type == "radio")
{
// For the first element prev will be null, hence push it into array and set the prev var.
if (prev == null)
{
prev = x.elements[i].name;
ansArray.push(x.elements[i].name);
} else {
// We will only push the next radio element if its not identical to previous.
if (prev != x.elements[i].name)
{
prev = x.elements[i].name;
ansArray.push(x.elements[i].name);
}
}
}
}
alert(ansArray);
}
HTML:
<body>
<form name="QnA" action="" method='post' ">
<input type="radio" name="g1" value="ANSTYPE1"> good </input>
<input type="radio" name="g1" value="ANSTYPE2"> avg </input>
<input type="radio" name="g2" value="ANSTYPE3"> Type1 </input>
<input type="radio" name="g2" value="ANSTYPE2"> Type2 </input>
<input type="submit" value='SUBMIT' onClick="javascript:getUniqueRadios()"></input>
</form>
</body>
Need to catch any undefined within the entire structure space of the an object literal. The issue is that the location of the undefined will not be predictable:
.object
.result2[0] <--undefined could show its ugly face here, or anywhere above or below!
.thumbnails[0]
.type
.name
.['open']
This doesn't work:
if ( typeof object.result2[0].thumbnails[0]..... type == 'undefined'){
console.log("err'd out")
handleError();
}
So I guess I am looking for a solution that follows: if anything within object is undefined do something, or am I barking up the wrong tree?
If you're doing this sort of thing a lot then a little helper function is useful:
function dig_out(o, path, def) {
var parts = path.split('.');
for(var i = 0; i < parts.length; ++i) {
if(typeof o == 'undefined')
return def;
o = o[parts[i]];
}
return o;
}
obj = { a: [1, [2, { b: 10 } ]]};
var x = dig_out(ob, 'a.1.1.b'); // x is now 10
The trick is to realize that this:
object.results2[0].thumbnails[0].type.name["open"]
can also be written as:
object['results2'][0]['thumbnails'][0]['type']['name']['open']
And that can be easily represented as a string:
'results2.0.thumbnails.0.type.name.open'
that is easy to understand and parse.
You could also represent the path as an array (as CD Sanchez does) but then you'd have to do something with the default value, def.
You could also allow the path argument to be an array:
function dig_out(o, path, def) {
var parts = path instanceof Array ? path : path.split('.');
for(var i = 0; i < parts.length; ++i) {
if(typeof o == 'undefined')
return def;
o = o[parts[i]];
}
return o;
}
obj = { a: [1, [2, { b: 10 } ]]};
var x = dig_out(obj, 'a.1.1.b'); // x is now 10
var y = dig_out(obj, ['a', 1, 1, 'b']); // y is now 10
Then you'd have some flexibility as to which argument format was easiest to work with and it wouldn't even cost that much. Thanks to a small discussion with CD Sanchez for this idea.
Generally you use
if (object && object.result2[0] && object.results2[0].thumbnails[0] && object.results2[0].thumbnails[0].type && object.results2[0].thumbnails[0].type.name) {
object.results2[0].thumbnails[0].type.name["open"]
}
The fact that this looks ugly is a problem with your nesting and that things can be undefined at each level.
Simple try-catch block will do the trick, without need to test each level.
If you really want to keep your code clean, you could make a simple function to check if all the keys exist.
function pathExists() { // untested, but the basis is sound
var obj = arguments[0], path = Array.prototype.slice.call(arguments, 1), cursor = obj;
for (var i = 0; i < path.length; ++i) {
if (typeof cursor[path[i]] == "undefined") return false;
cursor = cursor[path[i]];
}
return cursor;
}
if (!pathExists(object, "result2", 0, "type", "name", "open"))
console.log("bork");
This question already has answers here:
Length of a JavaScript object
(43 answers)
Closed 3 years ago.
Is there any built-in function that can return the length of an object?
For example, I have a = { 'a':1,'b':2,'c':3 } which should return 3. If I use a.length it returns undefined.
It could be a simple loop function, but I'd like to know if there's a built-in function?
There is a related question (Length of a JSON object) - in the chosen answer the user advises to transform object into an array, which is not pretty comfortable for my task.
For browsers supporting Object.keys() you can simply do:
Object.keys(a).length;
Otherwise (notably in IE < 9), you can loop through the object yourself with a for (x in y) loop:
var count = 0;
var i;
for (i in a) {
if (a.hasOwnProperty(i)) {
count++;
}
}
The hasOwnProperty is there to make sure that you're only counting properties from the object literal, and not properties it "inherits" from its prototype.
This should do it:
Object.keys(a).length
However, Object.keys is not supported in IE8 and below, Opera and FF 3.6 and below.
Live demo: http://jsfiddle.net/simevidas/nN84h/
Can be done easily with $.map():
var len = $.map(a, function(n, i) { return i; }).length;
Have you taken a look at underscore.js (http://underscorejs.org/docs/underscore.html)? It's a utility library with a lot of useful methods. There is a collection size method, as well as a toArray method, which may get you what you need.
_.size({one : 1, two : 2, three : 3});
=> 3
Summarizing all together, here is a universal function (including ie8 support):
var objSize = function(obj) {
var count = 0;
if (typeof obj == "object") {
if (Object.keys) {
count = Object.keys(obj).length;
} else if (window._) {
count = _.keys(obj).length;
} else if (window.$) {
count = $.map(obj, function() { return 1; }).length;
} else {
for (var key in obj) if (obj.hasOwnProperty(key)) count++;
}
}
return count;
};
document.write(objSize({ a: 1, b: 2, c: 3 }));
// 3
In jQuery i've made it in a such way:
len = function(obj) {
var L=0;
$.each(obj, function(i, elem) {
L++;
});
return L;
}
So one does not have to find and replace the Object.keys method, another approach would be this code early in the execution of the script:
if(!Object.keys)
{
Object.keys = function(obj)
{
return $.map(obj, function(v, k)
{
return k;
});
};
}
Also can be done in this way:
Object.entries(obj).length
For example:
let obj = { a: 1, b: 2, };
console.log(Object.entries(obj).length); //=> 2
// Object.entries(obj) => [ [ 'a', 1 ], [ 'b', 2 ] ]
Here's a jQuery-ised function of Innuendo's answer, ready for use.
$.extend({
keyCount : function(o) {
if(typeof o == "object") {
var i, count = 0;
for(i in o) {
if(o.hasOwnProperty(i)) {
count++;
}
}
return count;
} else {
return false;
}
}
});
Can be called like this:
var cnt = $.keyCount({"foo" : "bar"}); //cnt = 1;
One more answer:
var j = '[{"uid":"1","name":"Bingo Boy", "profile_img":"funtimes.jpg"},{"uid":"2","name":"Johnny Apples", "profile_img":"badtime.jpg"}]';
obj = Object.keys(j).length;
console.log(obj)
For those coming here to find the item count of something that is already a jQuery object:
.length is what you are looking for:
Example:
len = $('#divID').length;
alert(len);
If you want to avoid new dependencies you could make your own smart objects. Of course only if you want to do more that just get it's size.
MyNeatObj = function (obj) {
var length = null;
this.size = function () {
if (length === null) {
length = 0;
for (var key in obj) length++;
}
return length;
}
}
var thingy = new MyNeatObj(originalObj);
thingy.size();
You might have an undefined property in the object.
If using the method of Object.keys(data).length is used those properties will also be counted.
You might want to filter them out out.
Object.keys(data).filter((v) => {return data[v] !== undefined}).length
You may use something like Lodash lib and _.toLength(object) should give you the length of your object
You could add another name:value pair of length, and increment/decrement it appropriately. This way, when you need to query the length, you don't have to iterate through the entire objects properties every time, and you don't have to rely on a specific browser or library. It all depends on your goal, of course.
I need to do operations like compare that two number arrays have the same values, or two objects have the same member values. Is there a method that does this for me already (either ECMAScript or jQuery)?
For example, the function should return true that these both are the same:
var a = [1,2,3,4];
var b = [1,2,3,4];
Or with objects, the function should return that these two are the same:
var a = { id: 99, name: "Chris" };
var b = { name: "Chris", id: 99 };
I'm thinking maybe just JSON.stringify(a) === JSON.stringify(b)? Any problem with that?
Try the equiv library by Philippe Rathé. (Unfortunately the main site seems to be down, so I linked to js-test-driver source.)
Here's a pretty silly way to compare two objects containing scalar values:
function same(object1, object2) {
var merged = $.extend({}, object1, object2);
for (var key in merged) {
if (!object1.hasOwnProperty(key) ||
!object2.hasOwnProperty(key) ||
object1[key] != merged[key]) {
return false;
}
}
return true;
}
It relies on jQuery's extend and fails if object2 inherits properties from a prototype, since extend copies those, too.
function areEquiv ( a, b ) {
var eqCount = 0,
sizeCount = 0,
othCount = 0,
i;
if (typeof a.concat === "function") { // if comparing arrays
for (i = 0; i < a.length; i++) {
othCount = sizeCount = sizeCount + 1;
if (a[i] === b[i]) eqCount++;
}
} else { // if comparing objects
for (i in a) {
if (a.hasOwnProperty(i)) {
sizeCount = sizeCount + 1;
if (a[i] === b[i]) eqCount++;
}
}
for (i in b) {
if (b.hasOwnProperty(i)) {
othCount = othCount + 1;
}
}
}
return (a.length == b.length && eqCount == sizeCount && sizeCount == othCount);
}
Note that this will only work as long as the array or object contains simple values and isn't an array of objects or object with a parameter that's also an object.