Javascript code infinite loop

I'm making a function, which takes an array of values and returns an array with only unique values. For example:

var strings = ["audi", "audi", "bmw", "bmw","bmw","bmw","audi","audi", "8-()"];

Result should be:

alert( unique(strings) ); // audi, bmw, 8-()

I don't understand why my function goes into infinite loop, could anyone help please? Here is the function:

function unique(arr) {
   var result = [];
   result.push(arr[0]);

   for (var i = 1; i < arr.length; i++) {
       for (var j = 0; j < result.length; j++) {
           if  (result[j] != arr[i]) {
              result.push(arr[i]); 
           }
       }
   }

   return result;
} 

Answers:

Answer

There is no need for nested loop. you can check the result for available values with Array.prototype.indexOf or Array.prototype.includes methods.

var strings = ["audi", "audi", "bmw", "bmw", "bmw", "bmw", "audi", "audi", "8-()"];

function unique(arr) {
  var result = [];
  result.push(arr[0]);

  for (var i = 1; i < arr.length; i++) {
    if (result.indexOf(arr[i]) === -1)
      result.push(arr[i]);


  }
  return result;
}
console.log(unique(strings))

BTW chef suggest is:

var strings = ["audi", "audi", "bmw", "bmw", "bmw", "bmw", "audi", "audi", "8-()"];
console.clear();

var result = strings.filter(function(s){ return this[s] ? false : (this[s] = true); }, Object.create(null))

console.log(result);

Answer

You can make it very simpler with Set and spread operators belongs to ES6,

var unique = src => [...new Set(src)]

By the way your logic is wrong. It will not run into an infinite loop. But it will give you an undesirable result.

Answer

You can reduce the time complexity of this

var strings = ["audi", "audi", "bmw", "bmw","bmw","bmw","audi","audi", "8-()"];

var unique = [];

strings.forEach(function(str){
  if (unique.indexOf(str) < 0) {
     unique.push(str)
  }
});

return unique;
Answer

You can make it simpler: using Array.reduce

var values = [1,2,3,4,5,5,5,5,5,6,6,6,62,2,2]

function getUniq(array) {
  return array.reduce(function(u, value) {
    if (u.indexOf(value) < 0) u.push(value)
    return u;
  }, [])
}

console.log(getUniq(values))

Answer

You can use Set also

var strings = ["audi", "audi", "bmw", "bmw","bmw","bmw","audi","audi", "8-()"];
var uniq = new Set(strings);

// if you need in array 
uniq = Array.from(uniq);
Answer

You could also use a dictionary/hashtable for this. Then the total runtime should be O(N) for looping through arr once:

function unique(arr) {
    unique = {}
    for(var i=0; i<arr.length; i++) {
        unique[arr[i]]=true
    }
    return Object.keys(unique)
}   

JSFiddle

Answer

You could change the inner loop a bit and use a variable found for checking if the value is in the result array.

This variable is also needed to check if the value is to push to the result set.

Additionally you could use a break to exit the inner loop if a duplicate value is found.

function unique(arr) {
    var result = [],
        found;

    result.push(arr[0]);
    for (var i = 1; i < arr.length; i++) {
        found = false;                            // initial set to false
        for (var j = 0; j < result.length; j++) {
            if (result[j] === arr[i]) {
                found = true;                     // set to true to skip push
                break;                            // exit loop
            }
        }
        found || result.push(arr[i]);             // push only, if not found
    }
    return result;
}

var strings = ["audi", "audi", "bmw", "bmw", "bmw", "bmw", "audi", "audi", "8-()"];

console.log(unique(strings)); // audi, bmw, 8-()

A shorter ES6 proposal with Array#filter and a hash table as closure.

function unique(arr) {
    return arr.filter((temp => a => !temp[a] && (temp[a] = true))(Object.create(null)));
}

var strings = ["audi", "audi", "bmw", "bmw", "bmw", "bmw", "audi", "audi", "8-()"];

console.log(unique(strings)); // audi, bmw, 8-()

Answer

another fastest way, it is taking 2 milli seconds check the performance

var dupEleArr = [1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 20, 3, 3, 3, 32, 324, 5, 52];
var uniqueArr = dupEleArr.sort(function(a,b){
    return a-b;
}).filter(function(ele,i,arr){
   return arr.length > 3 ? arr[i] != arr[i+1] : (arr.length == 2) ? (arr[i] != arr[i+1]) : true;
});

check jsfiddle

Answer

push() Pushes a new object to the beginning of an array and pushes everything back!

Let's view the state of your arrays in the program:

arr = [A,B]    result = [A]    i = 1

j = 0 -> arr[i] = B and result[j] = A    
so we use push: result = [B,A] and j++

j = 1 -> arr[i] = B and result[j] = A
so we use push: result = [B,B,A] and j++

j = 2 -> arr[i] = B and result[j] = A
so we use push: result = [B,B,B,A] and j++

Your array keeps increasing and the check will never fail, since you append to the beginning of your array and not the end.

But even if you appended your new Item to the end, you would not get unique results, since you have to check every element in result and only if not any of the results is the same you should add your new element to the result array.

For better solutions see the other answers -> Use a Set with contains()

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.