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
|
Show 5 more comments
9 Answers
Reset to default 7You 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()
result.push(arr[i])
makesresult.length
increase by 1. – Pointy Commented Jul 16, 2016 at 14:07result
array will never stop to grow – webdeb Commented Jul 16, 2016 at 14:08console.log()
statements in the loop(s)? – nnnnnn Commented Jul 16, 2016 at 14:08arr[i]
item is not equal to the first value inresult
then you add it toresult
even though it may be equal to one of the later values inresult
. And if it's not equal to any of the existingresult
values you'll add it multiple times... – nnnnnn Commented Jul 16, 2016 at 14:11