Uniqualize array in Javascript? [duplicate] - javascript

This question already has answers here:
Remove duplicate values from JS array [duplicate]
(54 answers)
Closed 8 years ago.
I have the following script that's supposed to uniqualize array:
function uniques(arr) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
for (var j = 0; j < arr[i].length; j++) {
if (a.indexOf(arr[i][j]) === -1 && arr[i][j] !== '') {
a.push(arr[i][j]);
}
}
return a;
}
However, when it receives only one element, it just breaks it into the letters (which is understandable).
Do you know how I make it check if it's receiving only one element and then returns it back?
Thanks!

I'm not sure why you need the nested loop - you only need a single loop if you're processing a non-nested array:
function uniques(arr) {
if (arr.length === 1) { return arr };
var a = [];
for (var i = 0, l = arr.length; i < l; i++) {
if (a.indexOf(arr[i]) === -1) {
a.push(arr[i]);
}
}
return a;
}
DEMO
If you want to process nested arrays, use a recursive function. Here I've used underscore's flatten method as the basis:
function toType(x) {
return ({}).toString.call(x).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
function flatten(input, output) {
if (!output) { output = []; }
for (var i = 0, l = input.length; i < l; i++) {
var value = input[i];
if (toType(value) !== 'array' && output.indexOf(value) === -1) {
output.push(value);
} else {
flatten(value, output);
}
}
return output.sort(function (a, b) { return a - b; });
};
var arr = [1, 2, 3, [[4]], [10], 5, 1, 3];
flatten(arr); // [ 1, 2, 3, 4, 5, 10 ]
DEMO

I think the solution is this:
function uniques(arr) {
if (arr.length > 1) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
for (var j = 0; j < arr[i].length; j++) {
if (a.indexOf(arr[i][j]) === -1 && arr[i][j] !== '') {
a.push(arr[i][j]);
}
}
return a;
}
else
{
return arr;
}
}

What you're trying to do is a linear search on the created matrix for each item in the original one.
The solution below will accomplish this, but at a great cost. If your original matrix is 50x50 with unique values in each cell, it will take you 50^3 (=125000) loops to exit the function.
The best technique to search, in programming science, takes O(log(N)) that means that if you'll use it on your problem it will take log(50^2) (=11) loops.
function uniques(arr) {
var items = [];
var a = arr.map(function(row, i) {
return row.map(function(cell, j) {
if (items.indexOf(cell) >= 0) {
items.push(cell);
return cell;
}
});
});
}

Related

How to return the first occurrence of repeated item in an array using for loop?

I am trying to build logic currently with arrays and data structure. I am trying to implement the logic using for loop
function getRepeatingNumber(arr) {
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
return arr[i];
}
}
}
return undefined;
}
getRepeatingNumber([2, 3, 6, 5, 2]);
the above function takes in array and returns a repeated item in the array so in the above case it will return 2. But what if I have an array something like this arr[2,3,3,6,5,2] in this case it should return 3 but as the outer loop has index [0] which is 2 as the reference it will return 2 as the answer.
How to implement a function that returns the first occurrence of the repeated item.
Instead of iterating with j in the part after i, iterate the part before i:
function getRepeatingNumber(arr){
for (var i = 1; i < arr.length; i++) {
for (var j = 0; j < i; j++) {
if (arr[i] === arr[j]) {
return arr[i];
}
}
}
}
console.log(getRepeatingNumber([2,3,3,6,5,2]));
Note that an explicit return undefined is not needed, that is the default behaviour already.
You could also use indexOf to shorten the code a bit:
function getRepeatingNumber(arr){
for (var i = 1; i < arr.length; i++) {
if (arr.indexOf(arr[i]) < i) {
return arr[i];
}
}
}
console.log(getRepeatingNumber([2,3,3,6,5,2]));
You could even decide to make use of find -- which will return undefined in case of no match (i.e. no duplicates in our case):
function getRepeatingNumber(arr){
return arr.find((a, i) => {
if (arr.indexOf(a) < i) {
return true;
}
});
}
console.log(getRepeatingNumber([2,3,3,6,5,2]));
If you do this for huge arrays, then it would become important to have a solution that runs with linear time complexity. In that case, a Set will be useful:
function getRepeatingNumber(arr){
var set = new Set;
return arr.find(a => {
if (set.has(a)) return true;
set.add(a);
});
}
console.log(getRepeatingNumber([2,3,3,6,5,2]));
And if you are into functions of functions, and one-liners, then:
const getRepeatingNumber = r=>(t=>r.find(a=>[t.has(a),t.add(a)][0]))(new Set);
console.log(getRepeatingNumber([2,3,3,6,5,2]));
You need a data structure to keep track of first occurring index.
My recommendation is to use an array to store all the index of repeating numbers. Sort the array in ascending order and return the item at first index from the array.
function getRepeatingNumber(arr){
var resultIndexArr = [];
var count = 0;
var flag = 0;
for(var i=0;i<arr.length;i++)
{
for(var j=i+1;j<arr.length;j++)
{
if(arr[i] === arr[j])
{
flag = 1;
resultIndexArr[count++] = j;
}
}
}
resultIndexArr.sort((a, b) => a - b);
var resultIndex = resultIndexArr[0];
if(flag === 1)
return arr[resultIndex];
else
return;
}
console.log(getRepeatingNumber([2,3,6,5,2])); // test case 1
console.log(getRepeatingNumber([2,3,3,6,5,2])); // test case 2
console.log(getRepeatingNumber([2,5,3,6,5,2])); // test case 3
This will return correct result, but this is not the best solution. The best solution is to store your items in an array, check for each iteration if the item already exists in your array, if it exists then just return that item.
as a javascript dev you should be comfortable wit functional programming & higher-order functions so check the doc to get more understanding of some useful functions: like filter - find - reduce - findIndex map ...
Documentation
Now to answer your question:
at first you should think by step :
Get the occurrence of an item in an array as function:
const arr = [2, 5, 6, 2, 4, 5, 6, 8, 2, 5, 2]
const res = arr.reduce((numberofOcc, item) => {
if (item === 2)
numberofOcc++
return numberofOcc
}, 0);
console.log(`result without function ${res}`);
/* so my function will be */
const occurenceFun = (num, arr) => {
return arr.reduce((numberofOcc, item) => {
if (item === num)
numberofOcc++
return numberofOcc
}, 0);
}
console.log(`result using my function ${occurenceFun(2, arr)}`);
Now i have this function so i can use it inside another function to get the higher occurrence i have in an array
const arr = [1, 2, 5, 6, 8, 7, 2, 2, 2, 10, 10, 2]
const occurenceFun = (num, arr) => {
return arr.reduce((numberofOcc, item) => {
if (item === num)
numberofOcc++
return numberofOcc
}, 0);
}
/*let's create our function*/
const maxOccurenceFun = arr => {
let max = 0;
arr.forEach(el => {
if (max < occurenceFun(el, arr)) {
max = el
}
})
return max;
}
console.log(`the max occurence in this array is : ${maxOccurenceFun(arr)}`);

Returning first n elements of an array Javascript

I am writing a function that will return the first n elements of an array and if n is undefined then return the first element.
*Edit: I solved the problem.
_.first = function(array, n) {
var result = [];
if (n == undefined) {
return array[0];
}
var m;
if (array.length < n) {
m = array.length;
} else {
m = n;
}
for (var i = 0; i < m; i++) {
result.push(array[i]);
} return result;
};
This program is basically checking if the n value is bigger than the array's length, if it is, then it exits.
If n is not a number it exits. If it is it executes the program and logs the values of indexes with for loop until i reaches the n value. Also, it pushes the values to the empty array, so you can get the values from the array for later use.
var arr1 = [2, 3, 4, 5, 6, 7, 8];
var arr2 = []; //empty array
function arrNreturn(arr, n){
if(typeof n != 'number'){
console.log('n is not a number');
return false; //exit the program
}
if(n > arr.length){
console.log("the n value is bigger than the length");
}else{
for(var i = 0; i < n; i++){
console.log(arr[n]);
arr2.push(arr[n]);
}
}
}
arrNreturn(arr1, 10);
1_.first = function(array, n) {
2 var result = [];
3 for (var i = 0; i < n; i++) {
4 result.push(array[i]);
5 return result;
6 } return array[0];
7};
the problem is on the 5th line, you seem to be returning the first and not taking into account the n parts
a solution might be
_first = function(array, n){
var result = [];
if(n === undefined) return array[0];
for (var i = 0; i < n; i++) {
result.push(array[i]);
}
return result;
}
Basic is
const newArr = function(arr) {return n }
Shorthand
const newArr = arr => { return n}

Why is this function returns an empty array?

I just don't understand why does this function return an empty array instead of newArr = [1, 2, 3, etc.] depending on the length of the array.
function randomFunction(num) {
var newArr = [];
for(var i = 1; i < num.length; i++) {
newArr.push(i);
}
return newArr;
};
If num is supposed to be the length of the new array, and the last number of the range of values, you have to use it directly, instead of using length (which is meant to be used for an array):
function randomFunction(num) {
var newArr = [];
for(var i = 1; i <= num; i++) {
newArr.push(i);
}
return newArr;
};
var array = randomFunction(5);
console.log(array);
Also, you might want use <= instead of <, in case you want to start the value by 1 and go through n, and not n - 1.
function randomFunction(num) {
var newArr = [];
for(var i = 1; i < num /* number has no length */; i++) {
newArr.push(i);
}
return newArr;
};
Es6 alternative for fun:
return new Array(num).fill().map((r, i) => i)
randomFunction(8) ; for example
A number doesn't have length at all. It's already a value.
You do not need length attribute at all. just
for(var i = 1; i < num; i++) {
newArr.push(i);
}
function randomFunction(num) {
var newArr = [];
for (var i = 1; i < num; i++) {
newArr.push(i);
}
return newArr;
};
console.log(randomFunction(8))
num is already a number. You don't need use .lenght property
function randomFunction(num) {
var newArr = [];
for(var i = 1; i <= num; i++) {
newArr.push(i);
}
return newArr;
};
randomFunction(5); // [ 1, 2, 3, 4, 5 ]

Remove sub-array contains common elements

As the title, if the input is [[1,2], [3,4], [1,3], [5,6], [6,5]], output should be [[1,2,3,4], [5,6]].
It's wrong on the recursive part. In my code, after running it, I will get [[1,2,3],[1,3,4],[5,6]], which means I need once more merge, but I'm confused how to continue the code until no sub-array contains common element.
Here is my code
function need_merge_or_not(arr)
{
for (var i = 0; i <= arr.length-1; i++) {
for (var j = i+1; j <= arr.length-1; j++) {
var arr_new = arr[i].concat(arr[j]);
//remove deplicates
var arr_merge = arr_new.filter(function (item, pos) {return arr_new.indexOf(item) == pos});
if (arr_merge.length < arr_new.length) {
return true;
}
}
}
return false;
}
function merge(arr)
{
if (arr.length >= 2) {
for (var i = 0; i <= arr.length-1; i++) {
for (var j = i+1; j <= arr.length-1; j++) {
var arr_new = arr[i].concat(arr[j]);
var arr_merge = arr_new.filter(function (item, pos) {return arr_new.indexOf(item) == pos});
if (arr_merge.length < arr_new.length) {
arr.splice(arr.indexOf(arr[i]), 1);
arr.splice(arr.indexOf(arr[j]),1);
arr.push(arr_merge);
}
}
if (need_merge_or_not(arr)) {
return merge(arr);
}
}
}
return arr;
}
I figured it out. Here is the code:
function merge(arr){
var input = [];
for(var i = 0; i < arr.length; i++){
input.push(arr[i]);
}
if (arr.length >= 2) {
for (var i = 0; i < arr.length; i++) {
for (var j = i+1; j < arr.length; j++) {
var arr_new = arr[i].concat(arr[j]);
//remove duplicates
var arr_merge = arr_new.filter(function (item, pos) {return arr_new.indexOf(item) == pos});
if (arr_merge.length < arr_new.length) {
arr.splice(arr.indexOf(arr[i]), 1, arr_merge);
arr.splice(arr.indexOf(arr[j]),1);
j--;
}
}
}
if (!arraysEqual(input, arr)) {merge(arr)};
}
return arr;
//Input:[[1,2], [3,4], [1,3], [5,6], [6,5]]
//Output:[[1,2,3,4], [5,6]]
}
function arraysEqual(a, b) {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
You could use two hash tables, one for the items and their groups and on for the result sets.
Basically the algorithm generates for the same group an object with a property and an array, because it allowes to keep the object reference while assigning a new array.
The main part is iterating the outer array and then the inner arrays and check inside, if it is the first item, then check the hash table for existence and if not exists, generate a new object with a values property and an empty array as value. Also assign the actual object to sets with item as key.
In a next step, the hash table is checked again and if not exist, then assign the object of the first element.
To maintain only unique values, a check is made and if the item does not exist, the item is pushed to the hash table's values array.
Then a part to join arrays follows by checking if the object of the first item is not equal to object of the actual item. If so, it delete from sets the key from the actual items's values first item and concat the array of the actual items to the first item's object's values. Then the values object is assigned to the actual item's object.
Later the sets are maped to the result set with iterating the sets object and the values property is taken as value.
var array = [[1, 2], [3, 4], [1, 3], [5, 6], [6, 5]],
groups = {},
sets = {},
result;
array.forEach(function (a) {
a.forEach(function (b, i, bb) {
if (i === 0 && !groups[b]) {
groups[b] = { values: [] };
sets[b] = groups[b];
}
if (!groups[b]) {
groups[b] = groups[bb[0]];
}
if (groups[b].values.indexOf(b) === -1) {
groups[b].values.push(b);
}
if (groups[bb[0]] !== groups[b]) {
delete sets[groups[b].values[0]];
groups[bb[0]].values = groups[bb[0]].values.concat(groups[b].values);
groups[b].values = groups[bb[0]].values;
}
});
});
result = Object.keys(sets).map(function (k) {
return sets[k].values;
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Creating a global function that withholds for loops

How do I create a for loop that can be used in other functions?
How do I create a global variable with for loops?
arrayNr1 = [4,8,13,2]
arrayNr2 = [1,2,3,13]
function globalLoop(array1, array2) {
for(var i=0; i<array1.length; i++) {
for(var j=0; j<array2.length; j++){
if(array1[i] == array2[j]) {
return array2[j]
}
}
}
}
console.log(globalLoop(arrayNr1,arrayNr2)); //-> 13
Why is it only returning 13 instead of 13 and 2?
The first time the if statement is true, the function will return.
The loop won't keep going and return more things.
A function can only return a single thing, and a return statement will stop the function from running further.
If you want to find every match, then you need to store matches somewhere (such as another array) and return after the loops have finished.
Check it:
arrayNr1 = [4,8,13,2];
arrayNr2 = [1,2,3,13];
arrayFinal = [];
function globalLoop(array1, array2) {
for(var i=0; i<array1.length; i++) {
for(var j=0; j<array2.length; j++){
if(array1[i] == array2[j]) {
arrayFinal.push(array2[j])
}
}
}
}
globalLoop(arrayNr1,arrayNr2);
console.log(arrayFinal);
You exit the function at the first find.
return array2[j]
You could collect the values with an array.
function globalLoop(array1, array2) {
var result = [], i, j;
for (i = 0; i < array1.length; i++) {
for (j = 0; j < array2.length; j++){
if (array1[i] == array2[j]) {
result.push(array1[i]);
break;
}
}
}
return result;
}
var arrayNr1 = [4, 8, 13, 2],
arrayNr2 = [1, 2, 3, 13];
console.log(globalLoop(arrayNr1,arrayNr2));
You are iterating over arrayNr1 first and the first match in both arrays is (13, 13). The return statement stops the loop on the first match, it never gets to the second.
The following snippet collects all matches and returns an array.
arrayNr1 = [4,8,13,2]
arrayNr2 = [1,2,3,13]
function globalLoop(array1, array2) {
var equal_elements = [];
for(var i=0; i<array1.length; i++) {
for(var j=0; j<array2.length; j++){
if(array1[i] == array2[j]) {
// collect matches
equal_elements.push(array2[j]);
}
}
}
return equal_elements;
}
console.log(globalLoop(arrayNr1,arrayNr2));

Categories

Resources