JS - Sum Of Two Arrays where arrays can be of unequal length - javascript

I need function like this.
function sum(arr1, arr2) {
return totalArray
};
sum([1,2,3,4], [5,6,7,8,9]) // [6,8,10,12,9]
I tried it this way:
var array1 = [1, 2, 3, 4];
var array2 = [5, 6, 7, 8, 100];
var sum = array1.map((num, idx) => num + array2[idx]); // [6,8,10,12]

First you can get an array out of the function's arguments using Spread syntax (...), then sort it by array's length using Array.prototype.sort() and finally Array.prototype.reduce() to get the result array
Code:
const sum =(...arrays) => arrays
.sort((a, b) => b.length - a.length)
.reduce((a, c) => a.map((n, i) => n + (c[i] || 0)) || c)
// two arrays
const resultTwoArrays = sum([1, 2, 3, 4], [5, 6, 7, 8, 9])
console.log(resultTwoArrays) // [6, 8, 10, 12, 9]
// three arrays or more...
const resultThreeArrays = sum([1, 2, 3, 4], [5, 6, 7, 8, 9], [1, 2])
console.log(resultThreeArrays) // [7, 10, 10, 12, 9]
.as-console-wrapper { max-height: 100% !important; top: 0; }

At the risk of being unpopular due to using a loop:
function sum(arr1, arr2) {
let totalArray = [];
const totalLength = Math.max(arr1.length, arr2.length);
for (let i = 0; i < totalLength; i++) {
totalArray[i] = (arr1[i] || 0) + (arr2[i] || 0);
}
return totalArray;
}
The || 0 handles the possibility the array doesn't have an entry at i, because if it doesn't, the result of arrX[i] is undefined, and undefined || 0 is 0.

I try this way.
var array1 = [1, 2, 3, 4];
var array2 = [5, 6, 7, 8, 100];
var sum = array1.map((num, idx) => num + array2[idx]); // [6,8,10,12]
Very close, but map will stop at the end of array1, so you won't get the subsequent entries from array2. Just pick the longer of the two arrays, then handle the fact that the other array may not have an entry at arrayX[idx]. You can do that with the || 0 idiom:
function sum(array1, array2) {
var a, b;
if (array1.length > array2.length) {
a = array1;
b = array2;
} else {
a = array2;
b = array1;
}
return a.map((num, idx) => num + (b[idx] || 0));
}
console.log(sum([1, 2, 3, 4], [5, 6, 7, 8, 100]));
Alternately, you can use the new (but polyfill-able) Array.from to create the result array and use the callback to build the entries:
function sum(array1, array2) {
return Array.from(
{length: Math.max(array1.length, array2.length)},
(_, i) => (array1[i] || 0) + (array2[i] || 0)
);
}
console.log(sum([1, 2, 3, 4], [5, 6, 7, 8, 100]));
Mosho's answer is wonderfully simple, though.

Find the long and short array according to length. Iterate the short array with Array.map(), and take the value from the long array. Then add the leftovers from the long array using Array.slice(), and Array.concat():
function sum(arr1, arr2) {
const [l, s] = arr1.length >= arr2.length ? [arr1, arr2] : [arr2, arr1];
return s.map((n, i) => n + l[i])
.concat(l.slice(s.length));
};
console.log(sum([1,2,3,4], [5,6,7,8,9]));

Are we code golfing this? Here's a generator solution.
const summer = function*(a, b, i=0) {
while(i < a.length || i < b.length) yield (a[i] || 0) + (b[i++] || 0);
};
const sum = (a, b) => [...summer(a,b)];
console.log(sum([1,2,3,4], [5,6,7,8,9])) // [6,8,10,12,9]

You can have a custom logic something like this:
function sum(arr1, arr2) {
var length, selectedArray, nonSelectedArray;
if(arr1.length>arr2.length){
length = arr1.length;
selectedArray = arr2;
nonSelectedArray = arr1;
}else {
length = arr2.length;
selectedArray = arr1;
nonSelectedArray = arr2;
}
var totalArray = [];
for(var i=0; i<length; i++){
if(selectedArray[i]){
totalArray.push(selectedArray[i] + nonSelectedArray[i]);
} else {
totalArray.push(nonSelectedArray[i]);
}
}
return totalArray
};
var res = sum([1,2,3,4], [5,6,7,8,9]);
console.log(res);

Try with map():
function sum(arr1, arr2) {
var [a1, a2] = arr1.length > arr2.length ? [arr1, arr2] : [arr2, arr1]
var totalArray = a1.map(function(i, idx){
i = (i + a2[idx] || i + 0);
return i;
})
return totalArray;
};
console.log(sum([1,2,3,4], [5,6,7,8,9])) // [6,8,10,12,9]

Related

What is the efficient way to find an array inside an array?

Find an Array of Values Inside an Array
Lets say I have an array [1,2,3,8,2,3,4,5,6,7,8] and I want to find the first occurrence of the values [3,4,5,6] together, how might I do that? I can use Array.prototype.findIndex, but when I am looking for a large amount of values in a large array, it doesn't feel like the proper way to do it.
What fails:
let largeArray = [1,2,3,8,2,3,4,5,6,7,8];
let smallArray = [3,4,5,6];
//Problem: an array isn't a function
largeArray.findIndex(smallArray);
/*
Problem: always returns -1 because it checks each element
rather than looking for a group of elements.
*/
largeArray.indexOf(smallArray);
//Problem: same as using indexOf
largeArray.findIndex(item=>smallArray);
What works:
let largeArray = [1,2,3,8,2,3,4,5,6,7,8];
let smallArray = [3,4,5,6];
//Here is what works, but isn't ideal
largeArray.findIndex((item, index, arr) => {
let isTheOne = item == smallArray[0] &&
arr[index + 1] == smallArray[1] &&
arr[index + 2] == smallArray[2] &&
arr[index + 3] == smallArray[3];
return isTheOne;
});
//It returns 5, which is correct.
To Be Continued
I am currently using what works, but what if largeArray had the length of a million and smallArray had the length of 300. That would be 1 line of item == smallArray[0] &&, 298 lines of arr[index + x] == smallArray[x] &&, and 1 line of arr[index + x] == smallArray[x];. I don't want to use Array.prototype.map, Array.prototype.filter, Array.prototype.forEach, a for loop, or a while loop. This is because Array.prototype.map, Array.prototype.forEach, and the loops take a very long time to complete. I don't want to use Array.prototype.filter because that doesn't give me the index.
You were on the right track, you just want to use every() to look over the small index to check that each index matches
const largeArray = [1, 2, 3, 8, 2, 3, 4, 5, 6, 7, 8];
let smallArray = [3, 4, 5, 6];
const index = largeArray.findIndex(
(item, index, arr) =>
smallArray.every(
(n, sIndex) => n === arr[index + sIndex]
)
);
console.log(index);
You could add a check beforehand to not have to go in every... not sure what that would improve.
const index = largeArray.findIndex(
(item, index, arr) =>
item === smallArray[0] &&
smallArray.every(
(n, sIndex) => n === arr[index + sIndex]
)
);
Other approach is using strings
const largeArray = [1, 2, 3, 8, 2, 3, 4, 5, 6, 7, 8];
const smallArray = [3, 4, 5, 6];
const largeStr = largeArray.join(",");
const smallStr = smallArray.join(",");
const strIndex = largeStr.indexOf(smallStr);
const index = strIndex > -1 ? largeStr.substr(0,strIndex-1).split(",").length : -1;
console.log(index)
To figure out what is better is really based on your use case.
You can use .join to convert the arrays to strings, and use .indexOf to get the index given that you will remove the additional commas:
const getIndexOfSubArray = (arr=[], sub=[]) => {
const str = arr.join();
const subStr = sub.join();
const index = str.indexOf(subStr);
return index < 0 ? -1 : str.substr(0, index-1).split(',').length;
}
console.log( getIndexOfSubArray([1,2,3,8,2,3,4,5,6,7,8], [3,4,5,6]) );
You could iterate by hand and check the items with indexOf.
function getIndex(array, subarray) {
let p = -1,
first = subarray[0];
while ((p = array.indexOf(first, p + 1)) !== -1) {
let i = p,
complete = true;
for (const s of subarray) {
if (s !== array[i++]) {
complete = false;
break;
}
}
if (complete) return p;
}
return -1;
}
console.log(getIndex([1, 2, 3, 8, 2, 3, 4, 5, 6, 7, 8], [3, 4, 5, 6])); // 5
Here is a simple approach to this problem:
let largeArray = [1, 2, 3, 8, 2, 3, 4, 5, 6, 7, 8];
let smallArray = [3, 4, 5, 6];
let s = 0,
i = 0,
j = 0;
let SLen = smallArray.length,
LLen = largeArray.length;
while (i < LLen && j < SLen && SLen - j <= LLen - i) {
if (j == 0) {
s = i;
}
if (largeArray[i] == smallArray[j]) {
j++;
} else {
j = 0;
i = s;
}
i++;
}
let index = i - j;
if (j == SLen) {
console.log(`found at index ${index}`);
} else {
console.log('not found');
}

issue with merge sorted arrays problem using javascript

I am trying to solve merge 2 sorted arrays problem using javascript. Please find my solution below:
input:
const arr1 = [1, 4, 7, 8, 10];
const arr2 = [2, 3, 9];
output:
[1, 2, 3, 4, 7, 8, 9 10]
const arr1 = [1, 4, 7, 8, 10];
const arr2 = [2, 3, 9];
let arrayItem1 = arr1[0];
let arrayItem2 = arr2[0];
let i = 1;
let j = 1;
let mergedArray = [];
while(arrayItem2 || arrayItem1) {
arrayItem1 = arrayItem1 === undefined ? 0 : arrayItem1;
arrayItem2 = arrayItem2 === undefined ? 0 : arrayItem2;
if (arrayItem1 < arrayItem2) {
console.log('inside if');
console.log("first array", arrayItem1);
arrayItem1 = arr1[i];
i++;
mergedArray.push(arrayItem1);
} else {
console.log('inside else');
console.log("second array", arrayItem2);
arrayItem2 = arr2[j];
j++;
mergedArray.push(arrayItem2);
}
console.log("== merged array ==", mergedArray);
}
But it is going in infinite loop. Not sure where I am going wrong. Need a watchful pair of eyes here.
thanks
You need to check the index with the lengths of the arrays and add a final check for getting the rest of the arrays added to the merged array.
const
array1 = [1, 4, 7, 8, 10],
array2 = [2, 3, 9],
mergedArray = [];
let i = 0,
j = 0;
while (i < array1.length && j < array2.length) {
if (array1[i] < array2[j]) {
mergedArray.push(array1[i++]);
} else {
mergedArray.push(array2[j++]);
}
}
if (i < array1.length) mergedArray.push(...array1.slice(i));
if (j < array2.length) mergedArray.push(...array2.slice(j));
console.log(...mergedArray);
const arr1 = [1, 4, 7, 8, 10];
const arr2 = [2, 3, 9];
const mergedArrays = [...arr1, ...arr2];
// WITH SORT
const result = mergedArrays.sort((a, b) => Number(a) - Number(b));
console.log(result);
// WITHOUT SORT
const bubbleSort = (arr) => {
let done = false;
while (!done) {
done = true;
arr.forEach((el, i) => {
if (arr[i - 1] > arr[i]) {
done = false;
const tmp = arr[i - 1];
arr[i - 1] = arr[i];
arr[i] = tmp;
}
});
}
return arr;
};
const result2 = bubbleSort(mergedArrays)
console.log(result2)
You don't really need to go through all that trouble, you can merge your arrays by destructuring your arrays in new one and just use the Array.sort() method.
UPDATE:
Added sorting without using using Array.sort(), using a sorting algorithm Bubble sort
This will also work for non positive numbers
//[1, 2, 3, 4, 7, 8, 9 10]
const arr1 = [1, 4, 7, 8, 10];
const arr2 = [2, 3, 9];
let arrayItem1 = arr1[0];
let arrayItem2 = arr2[0];
let i = 1;
let j = 1;
let mergedArray = [];
while(arrayItem2 !== undefined || arrayItem1 !== undefined) {
if (arrayItem2 === undefined || arrayItem1 < arrayItem2) {
mergedArray.push(arrayItem1);
arrayItem1 = arr1[i];
i++;
} else {
mergedArray.push(arrayItem2);
arrayItem2 = arr2[j];
j++;
}
console.log('Merged array: ' + mergedArray)
}
Some issues:
The actions in the if block (and else block) occur in the wrong order. You first want to push the item, then increment the index, and then get the next value from the array so it will be used in the next comparison.
Don't assign the value 0 when a value is undefined. Just leave it undefined, otherwise you risk to push a 0 into the result that was never there in the input.
So:
const arr1 = [1, 4, 7, 8, 10];
const arr2 = [2, 3, 9];
let arrayItem1 = arr1[0];
let arrayItem2 = arr2[0];
let i = 1;
let j = 1;
let mergedArray = [];
while(arrayItem2 || arrayItem1) {
if (arrayItem2 === undefined || arrayItem1 < arrayItem2) {
mergedArray.push(arrayItem1);
i++;
arrayItem1 = arr1[i];
} else {
mergedArray.push(arrayItem2);
j++;
arrayItem2 = arr2[j];
}
}
console.log("== merged array ==", mergedArray);
const arr1 = [1, 4, 7, 8, 10];
const arr2 = [2, 3, 9];
var children = arr1.concat(arr2);
console.log (children.sort(function(a, b){return a - b}));
children.sort(function(a, b){return a - b});
const arr1 = [1, 4, 7, 8, 10];
const arr2 = [2, 3, 9];
var children = arr1.concat(arr2);
console.log (children.sort(function(a, b){return a - b}));

Get Indexes of Filtered Array Items

In JavaScript, I have the following array
var arr = [5, 10, 2, 7];
From that array, I would like to get an array containing only the indexes of the items that are less than 10. So, in the above example, the indexes array would be
var indexes = [0, 2, 3];
Now, I want something simlar to filter, but that would return the indexes.
If I try filter, this is how it will work
var newArr = arr.filter(function (d) {
return (d < 10);
});
// newArr will be: [5, 2, 7];
This is not what I want. I want something along the following lines (note this is a pseudo-code)
var indexes = arr.filter(function (d) {
/* SOMETHING ALONG THE FOLLOWING PSEUDOCODE */
/* return Index of filter (d < 10); */
});
// indexes will be: [0, 2, 3];
How can I do that? Thanks.
Use a reducer.
var arr = [5, 10, 2, 7];
var newArr = arr.reduce(function(acc, curr, index) {
if (curr < 10) {
acc.push(index);
}
return acc;
}, []);
console.log(newArr);
You can use a forEach loop:
const arr = [5, 10, 2, 7];
const customFilter = (arr, min) => {
const result = [];
arr.forEach((element, index) => {
if (element < min) {
result.push(index);
}
});
return result;
}
console.log(customFilter(arr, 10));
You can use array#reduce and add indexes whose value is greater than 10.
var arr = [5, 10, 2, 7];
var indexes = arr.reduce((r, d, i) => d < 10 ? (r.push(i), r) : r , []);
console.log(indexes);

Alternative to array.splice in JavaScript

I am currently working on a project where I store numeric values in a JS array. After some changes it should be removed again. I currently use the array.splice method like this:
function removeA(arr, element) {
var index = arr.indexOf(element);
if (index >= 0) {
arr.splice(index, 1 );
}
return arr;
}
But this seems to give me issues on Safari. This piece of code works in every browser, like Chrome, Firefox, Opera. But not on Safari. It even works in the Technical Preview of Safari.
Does anyone have an alternative?
Thanks in advance :)
You have to slice before and after the index, and concat the results. Note that Array.prototype.slice() doesn't mutate the original array like Array.prototype.splice() does.
var arr = [0, 1, 2, 3, 4, 5, 6, 7];
var index = 5;
var result = arr.slice(0, index).concat(arr.slice(index + 1));
console.log(result);
Or using ES6 and array spread:
var arr = [0, 1, 2, 3, 4, 5, 6, 7];
var index = 5;
var result = [...arr.slice(0, index), ...arr.slice(index + 1)];
console.log(result);
You can use the built-in filter()
var array = [1,2,3,7,4,5,6,7,12,54,7,691];
var array = array.filter(x => x !== 7);
console.log(array);
Another Alternative to array.splice in JavaScript is array.reduce
var arr =[1,2,3,2,4,5,6,2];
var newarr = arr.reduce((acc, elem) => elem !== 2 ? acc.concat(elem) : acc, []);
console.log(newarr);
Try the slice() method
arr = arr.slice(index, 1 );
Sorry for late but hopefully it is useful for someone else
var arr = [32, 33, 16, 40, 55, 2, 41, 3, 10];
document.write("Array : "+arr);
document.write("<br>");
document.write("Removed Elements : "+mySplice(arr,2,2));
document.write("<br>");
document.write("Processed Array : "+arr);
function mySplice(array,index,count) {
var fixIndex = -1;
var ret = [];
arr = array.filter(function(element) {
fixIndex++;
if((fixIndex >= index && fixIndex < (index+count))) {
ret[ret.length]=element;
return false;
} else {
return true;
}
});
return ret;
}
Or you can use simple version (NOTE: it is simple but reversed)
var arr = [32, 33, 16, 40, 55, 2, 41, 3, 10];
document.write("Array : "+arr);
document.write("<br>");
document.write("Processed Array : "+mySplice_simple(arr,2,2));
function mySplice_simple(arr,index,count) {
fixIndex = -1;
return arr.filter(function(i) {
fixIndex++;
return !(fixIndex >= index && fixIndex < (index+count));
});
}
Or if you have to remove just one element then use this
var arr = [32, 33, 16, 40, 55, 2, 41, 3, 10];
document.write("Array : "+arr);
document.write("<br>");
document.write("Processed Array : "+mySplice_simple_v2(arr,2));
function mySplice_simple_v2(arr,index,count) {
fixIndex = -1;
return arr.filter(function(i) {
fixIndex++;
return fixIndex != index;
});
}
Some more ideas:
Option A flatMap():
Return an empty [] in order to "filter" elements. Less efficient but might be useful in case you want to add new elements as well.
const a = [3, 4, 5, 6];
const filter = 2;
const r = a.flatMap((v, j) => j !== filter ? v : []);
console.log(`Result: %o`, r); // Result: [3, 4, 6]
Example for filter + insert
const a = [3, 4, 5, 6];
const filter = 2;
const insert = 1;
const value = 4.5;
const r = a.flatMap((v, j) => {
if (j === filter) return [];
if (j === insert) return [v, value];
return v;
});
console.log(`Result: %o`, r); // Result: [3, 4, 4.5, 6]
Option B Array.from():
const a = [3, 4, 5, 6];
const filter = 2;
const r = Array.from({length: a.length -1}, (_, i) => a[i >= filter ? i + 1: i]);
console.log(`Result: %o`, r); // Result: [3, 4, 6]
Option C "Destructure":
const a = [3, 4, 5, 6];
const filter = 2;
const {[filter]: _, ...o} = a;
const r = Object.values(o);
console.log(`Result: %o`, r); // Result: [3, 4, 6]

How to subtract elements of two arrays and store the result as positive array in javascript?

Assume i have 2 arrays,
A=[1,2,3,4,5,6]
B=[9,8,7,5,8,3]
When I subtract the elements of the array,
C=[-8,-6,-4,-1,-3,3]
How can I get the result of the subtraction as
C=[8,6,4,1,3,3]
You can use the javascript function Math.abs()
C.map(Math.abs);
Using Math.abs
function absSubtract(arr1, arr2) {
return arr2.map(function (el, i) {
return Math.abs(el - arr1[i]);
});
}
absSubtract(A, B); // [ 8, 6, 4, 1, 3, 3 ]
DEMO
Math.abs() is returning the absolute value of a number.
You could do something like
var A=[1,2,3,4,5,6]
var B=[9,8,7,5,8,3]
var C = [];
for(let i = 0; i < A.length; i++) {
C.push(Math.abs(A[i] - B[i]));
}
C = A.map( (x, i) => x - B[i] ).map( x => Math.abs(x) );
Assuming that A and B are the same length.
for (var i = 0; i < A.length; i++) {
C[i] = Math.abs(A[i] - B[i]);
}
A solution for the absolute difference. c = |a - b|
var a = [1, 2, 3, 4, 5, 6],
b = [9, 8, 7, 5, 8, 3],
c = a.map(function (v, i) { return Math.abs(v - b[i]); });
document.write('<pre>' + JSON.stringify(c, 0, 4) + '</pre>');

Categories

Resources