最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript code infinite loop - Stack Overflow

programmeradmin1浏览0评论

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;
} 

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;
} 
Share Improve this question asked Jul 16, 2016 at 14:05 qazerty23qazerty23 4912 gold badges6 silver badges17 bronze badges 10
  • 1 result.push(arr[i]) makes result.length increase by 1. – Pointy Commented Jul 16, 2016 at 14:07
  • your result array will never stop to grow – webdeb Commented Jul 16, 2016 at 14:08
  • Have you tried stepping through your code with the debugger, or adding some console.log() statements in the loop(s)? – nnnnnn Commented Jul 16, 2016 at 14:08
  • 1 I don't get an infinite loop when I run the above code, but the logic is faulty. If the current arr[i] item is not equal to the first value in result then you add it to result even though it may be equal to one of the later values in result. And if it's not equal to any of the existing result values you'll add it multiple times... – nnnnnn Commented Jul 16, 2016 at 14:11
  • 1 Well, in spite of all the answers that pretty much just show code, be sure to analyse what you were doing so you can understand what was wrong and how it would be fixed given your original approach. Understanding these sorts of problems is very important. – user1106925 Commented Jul 16, 2016 at 14:23
 |  Show 5 more comments

9 Answers 9

Reset to default 7

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.

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);

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;

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))

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);

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

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-()

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

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()

发布评论

评论列表(0)

  1. 暂无评论