43

I wanted to write a javascript function which checks if array contains duplicate values or not.

I have written the following code but its giving answer as "true" always.

Can anybody please tell me what am I missing.

function checkIfArrayIsUnique(myArray) 
    {
        for (var i = 0; i < myArray.length; i++) 
        {
            for (var j = 0; j < myArray.length; j++) 
            {
                if (i != j) 
                {
                    if (myArray[i] == myArray[j]) 
                    {
                        return true; // means there are duplicate values
                    }
                }
            }
        }
        return false; // means there are no duplicate values.
    }
Ranadheer Reddy
  • 4,202
  • 12
  • 55
  • 77
milan m
  • 2,164
  • 3
  • 26
  • 40

17 Answers17

117

An easy solution, if you've got ES6, uses Set:

function checkIfArrayIsUnique(myArray) {
  return myArray.length === new Set(myArray).size;
}

let uniqueArray = [1, 2, 3, 4, 5];
console.log(`${uniqueArray} is unique : ${checkIfArrayIsUnique(uniqueArray)}`);

let nonUniqueArray = [1, 1, 2, 3, 4, 5];
console.log(`${nonUniqueArray} is unique : ${checkIfArrayIsUnique(nonUniqueArray)}`);
Zameer Ansari
  • 28,977
  • 24
  • 140
  • 219
natetitterton
  • 1,200
  • 2
  • 7
  • 4
25
let arr = [11,22,11,22];

let hasDuplicate = arr.some((val, i) => arr.indexOf(val) !== i);
// hasDuplicate = true

True -> array has duplicates

False -> uniqe array

ofir_aghai
  • 3,017
  • 1
  • 37
  • 43
  • 2
    you could write as a one-liner (with some strict equality): `a.some((val, i) => a.indexOf(val) !== i);` – William Myers May 25 '17 at 13:26
  • if you want the array without the duplicates: `const filtered = a.filter((val, i) => a.indexOf(val) === i);` NB: these only work for arrays of primitive values – William Myers May 25 '17 at 13:44
  • If you use findIndex() instead of indexOf(), it will stop when it finds a match instead of continuing with the rest of the array. – bobpal Mar 01 '20 at 14:56
  • 1
    @bobpal both findIndex() and indexOf() will stop after find the first value and will not continue till the rest of the array. – ofir_aghai Mar 03 '20 at 15:43
23

This should work with only one loop:

function checkIfArrayIsUnique(arr) {
    var map = {}, i, size;

    for (i = 0, size = arr.length; i < size; i++){
        if (map[arr[i]]){
            return false;
        }

        map[arr[i]] = true;
    }

    return true;
}
CD..
  • 72,281
  • 25
  • 154
  • 163
21

You got the return values the wrong way round:

  • As soon as you find two values that are equal, you can conclude that the array is not unique and return false.

  • At the very end, after you've checked all the pairs, you can return true.

If you do this a lot, and the arrays are large, you might want to investigate the possibility of sorting the array and then only comparing adjacent elements. This will have better asymptotic complexity than your current method.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Thanks for your answer. I think my function was correct but the return values were being send the wrong way. – milan m Oct 29 '13 at 10:55
  • Also I was passing null values in the array and hence I was getting wrong answer. Anyways, my problem is solved. – milan m Oct 29 '13 at 10:56
  • @NPE how will sorting way have "better asymptotic complexity"? it increases the time complexity to O(nlogn) from O(n). the way does drop the space complexity from O(n) to O(1). Were you talking about space complexity? – Vishal Jan 14 '21 at 08:19
7

Assuming you're targeting browsers that aren't IE8,

this would work as well:

function checkIfArrayIsUnique(myArray) 
{
    for (var i = 0; i < myArray.length; i++) 
    {
        if (myArray.indexOf(myArray[i]) !== myArray.lastIndexOf(myArray[i])) { 
            return false; 
        } 
    } 
    return true;   // this means not unique
}
IanMac
  • 3
  • 3
MildlySerious
  • 8,750
  • 3
  • 28
  • 30
2

Another solution:

 Array.prototype.checkIfArrayIsUnique = function() {
    this.sort();    
    for ( var i = 1; i < this.length; i++ ){
        if(this[i-1] == this[i])
            return false;
    }
    return true;
    }
Cristik
  • 30,989
  • 25
  • 91
  • 127
sharad-garg
  • 359
  • 1
  • 6
  • 12
  • 2
    I'm not sure if this is the best solution, it's frowned upon to directly add onto a prototype of a native in javaScript, this should just be a regular function to prevent possible conflicts. – Michael Ryan Soileau Aug 14 '15 at 18:38
  • Note that this doesn't work if there are more than 2 duplicate values. – aarjithn Oct 20 '15 at 12:48
  • 1
    Why is this the best solution? You're adding to the prototype chain seemingly for no good reason and it is not as performant as the answers that do it within one loop (since you sort the array first). Perhaps explain why you think this is the best solution? – GrayedFox Aug 16 '19 at 13:30
  • Sorting costs 0(n*log(n)) while you can tell whether duplicates exist in O(n) - Far from best solution. – Gil Epshtain Sep 12 '19 at 08:54
  • Also, wouldn't `sort` mutate the array? That might be a big problem. – General Grievance May 06 '22 at 01:49
2

Here's an O(n) solution:

function hasDupes(arr) {
  /* temporary object */
  var uniqOb = {};
  /* create object attribute with name=value in array, this will not keep dupes*/
  for (var i in arr)
    uniqOb[arr[i]] = "";
  /* if object's attributes match array, then no dupes! */
  if (arr.length == Object.keys(uniqOb).length)
    alert('NO dupes');
  else
    alert('HAS dupes');


}
var arr = ["1/1/2016", "1/1/2016", "2/1/2016"];
hasDupes(arr);

https://jsfiddle.net/7kkgy1j3/

Sajjan Sarkar
  • 3,900
  • 5
  • 40
  • 51
2
function hasNoDuplicates(arr) {
    return arr.every(num => arr.indexOf(num) === arr.lastIndexOf(num));
}

hasNoDuplicates accepts an array and returns true if there are no duplicate values. If there are any duplicates, the function returns false.

Cristik
  • 30,989
  • 25
  • 91
  • 127
1

Without a for loop, only using Map().

You can also return the duplicates.

(function(a){
  let map = new Map();

  a.forEach(e => {
    if(map.has(e)) {
      let count = map.get(e);
      console.log(count)
      map.set(e, count + 1);
    } else {
      map.set(e, 1);
    }
  });

  let hasDup = false;
  let dups = [];
  map.forEach((value, key) => {
    if(value > 1) {
      hasDup = true;
      dups.push(key);
    }
  });
   console.log(dups);
   return hasDup;
 })([2,4,6,2,1,4]);
Morris S
  • 2,337
  • 25
  • 30
1

Late answer but can be helpful

function areThereDuplicates(args) {

    let count = {};
    for(let i = 0; i < args.length; i++){
         count[args[i]] = 1 + (count[args[i]] || 0);
    }
    let found = Object.keys(count).filter(function(key) {
        return count[key] > 1;
    });
    return found.length ? true : false; 
}

areThereDuplicates([1,2,5]);
johannesMatevosyan
  • 1,974
  • 2
  • 30
  • 40
1

If your array nests other arrays/objects, using the Set approach may not be what you want since comparing two objects compares their references. If you want to check that their contained values are equal, something else is needed. Here are a couple different approaches.

Approach 1: Map using JSON.stringify for keys

If you want to consider objects with the same contained values as equal, here's one simple way to do it using a Map object. It uses JSON.stringify to make a unique id for each element in the array.

I believe the runtime of this would be O(n * m) on arrays, assuming JSON.stringify serializes in linear time. n is the length of the outer array, m is size of the arrays. If the objects get very large, however, this may slow down since the keys will be very long. Not a very space-efficient implementation, but it is simple and works for many data types.

function checkArrayDupeFree(myArray, idFunc) {
    const dupeMap = new Map();
    for (const el of myArray) {
        const id = idFunc(el);
        if (dupeMap.has(id))
            return false;
        dupeMap.set(id, el);
    }
    return true;
}

const notUnique = [ [1, 2], [1, 3], [1, 2] ];
console.log(`${JSON.stringify(notUnique)} has no duplicates? ${checkArrayDupeFree(notUnique, JSON.stringify)}`);

const unique = [ [2, 1], [1, 3], [1, 2] ];
console.log(`${JSON.stringify(unique)} has no duplicates? ${checkArrayDupeFree(unique, JSON.stringify)}`);

Of course, you could also write your own id-generator function, though I'm not sure you can do much better than JSON.stringify.

Approach 2: Custom HashMap, Hashcode, and Equality implementations

If you have a lot of big arrays, it may be better performance-wise to implement your own hash/equality functions and use a Map as a HashMap.

In the following implementation, we hash the array. If there is a collision, map a key to an array of collided values, and check to see if any of the array values match according to the equality function.

The downside of this approach is that you may have to consider a wide range of types for which to make hashcode/equality functions, depending on what's in the array.

function checkArrayDupeFreeWHashes(myArray, hashFunc, eqFunc) {
    const hashMap = new Map();
    
    for (const el of myArray) {
        const hash = hashFunc(el);
        const hit = hashMap.get(hash);
    
        if (hit == null)
            hashMap.set(hash, [el]);
        else if (hit.some(v => eqFunc(v, el)))
            return false;
        else
            hit.push(el);
    }

    return true;
}

Here's a demo of the custom HashMap in action. I implemented a hashing function and an equality function for arrays of arrays.

function checkArrayDupeFreeWHashes(myArray, hashFunc, eqFunc) {
    const hashMap = new Map();
    
    for (const el of myArray) {
        const hash = hashFunc(el);
        const hit = hashMap.get(hash);
    
        if (hit == null)
            hashMap.set(hash, [el]);
        else if (hit.some(v => eqFunc(v, el)))
            return false;
        else
            hit.push(el);
    }

    return true;
}

function arrayHasher(arr) {
    let hash = 19;
    for (let i = 0; i < arr.length; i++) {
        const el = arr[i];
        const toHash = Array.isArray(el)
            ? arrayHasher(el)
            : el * 23;
        hash = hash * 31 + toHash;
    }

    return hash;
}

function arrayEq(a, b) {
    if (a.length != b.length)
        return false;

    for (let i = 0; i < a.length; i++) {
        if ((Array.isArray(a) || Array.isArray(b)) && !arrayEq(a[i], b[i]))
            return false;
        else if (a[i] !== b[i])
            return false;
    }

    return true;
}

const notUnique = [ [1, 2], [1, 3], [1, 2] ];
const unique = [ [2, 1], [1, 3], [1, 2] ];
console.log(`${JSON.stringify(notUnique)} has no duplicates? ${checkArrayDupeFreeWHashes(notUnique, arrayHasher, arrayEq)}`);
console.log(`${JSON.stringify(unique)} has no duplicates? ${checkArrayDupeFreeWHashes(unique, arrayHasher, arrayEq)}`);
General Grievance
  • 4,555
  • 31
  • 31
  • 45
0

The code given in the question can be better written as follows

function checkIfArrayIsUnique(myArray) 
    {
        for (var i = 0; i < myArray.length; i++) 
        {
            for (var j = i+1; j < myArray.length; j++) 
            {                  
                    if (myArray[i] == myArray[j]) 
                    {
                        return true; // means there are duplicate values
                    }

            }
        }
        return false; // means there are no duplicate values.
    }
Kiran
  • 896
  • 1
  • 6
  • 25
  • This seems to only improve the performance of that function, without fixing the problem the asked has/had. I might be wrong, in this case, can you update your answer with more details about how your code addresses the problem? – Cristik May 08 '22 at 06:48
0

Returns the duplicate item in array and creates a new array with no duplicates:

 var a = ["hello", "hi", "hi", "juice", "juice", "test"];
    var b = ["ding", "dong", "hi", "juice", "juice", "test"];
    var c = a.concat(b);
    var dupClearArr = [];

    function dupArray(arr) {

        for (i = 0; i < arr.length; i++) {
            if (arr.indexOf(arr[i]) != i && arr.indexOf(arr[i]) != -1) {
                console.log('duplicate item ' + arr[i]);
            } else {
                dupClearArr.push(arr[i])
            }

        }
        console.log('actual array \n' + arr + ' \nno duplicate items array \n' + dupClearArr)
    }

    dupArray(c);
Leopold Joy
  • 4,524
  • 4
  • 28
  • 37
0
const containsMatches = (a1, a2) => a1.some((v) => a2.includes(v));
readikus
  • 369
  • 1
  • 6
  • 17
-1
function checkIfArrayIsUnique(myArray) 
    {
      isUnique=true

        for (var i = 0; i < myArray.length; i++) 
        {
            for (var j = 0; j < myArray.length; j++) 
            {
                if (i != j) 
                {
                    if (myArray[i] == myArray[j]) 
                    {
                        isUnique=false
                    }
                }
            }
        }
        return isUnique;
    }

This assume that the array is unique at the start.

If find two equals values, then change to false

Don
  • 292
  • 2
  • 12
-1

i think this is the simple way

$(document).ready(function() {

  var arr = [1,2,3,9,6,5,6];
  
  console.log( "result =>"+ if_duplicate_value (arr));
  
});


function if_duplicate_value (arr){
    
    for(i=0;i<arr.length-1;i++){
        
        for(j=i+1;j<arr.length;j++){
            
            if(arr[i]==arr[j]){
                
                return true;
                
            }
            
        }
        
    }
    
    return false;
    
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
-1

var c=[2,2,3,3,5,5,4,4,8,8];

for(var i=0; i<b.length; i++){
    for(var j=i+1; j<b.length; j++){
        if(c[i]==c[j]){
            console.log(c[j]);
        }
    }
}
Tomal
  • 1
  • 2