How to multiply array values without nested loops - javascript

Problem:
Given an array of integers, return a new array such that each element at index i of the new array is the product of all the numbers in the original array except the one at i.
For example:
if our input was [1, 2, 3, 4, 5], the expected output would be [120, 60, 40, 30, 24].
If our input was [3, 2, 1], the expected output would be [2, 3, 6].
Solution 1 (With Nested loops): I'm able to solve this by nested loops like below:
const input = [1, 2, 3, 4, 5];
function output(items) {
const finalArray = [];
for (let i = 0; i < items.length; i++) {
let multipliedNum = 1;
items.forEach((item, indx) => {
if (i !== indx) {
multipliedNum = multipliedNum * item;
}
});
finalArray.push(multipliedNum)
}
return finalArray;
}
console.log(output(input))
I'm trying to find out another solution without nested loops inside output function? Any help or suggestion really appreciated.

If there are no zero values, you can loop through all the values once to get the product. Then just return the array where each the product is divided by each entry.
However, if there are zeros then there is a little more to be done to check how many there are. One zero is fine but more than 1 means that the value is zero for each entry.
const input = [1, 2, 3, 4, 5];
const input2 = [1, 2, 3, 4, 0];
const input3 = [1, 2, 3, 0, 0];
function output(items) {
let zeroCount = 0;
let totalProduct = 1;
for (let i = 0; i < items.length; i++) {
if (items[i] === 0) {
if (++zeroCount > 1) break;
continue;
}
totalProduct *= items[i];
}
if (zeroCount > 1) {
// more than 1 zero -> all values are 0
return new Array(items.length).fill(0);
} else if (zeroCount === 1) {
// only 1 zero -> only the value that is zero will be the totalProduct
return items.map(item => item === 0 ? totalProduct : 0);
}
// no zero in array -> divide the totalProduct by each item
return items.map(item => totalProduct / item);
}
console.log(output(input))
console.log(output(input2))
console.log(output(input3))

Based on what #Mike said in the comment here's the answer.
const input = [1, 2, 3, 4, 5];
const mulValues = input.reduce((acc, next) => acc * next);
const output = input.map(i => mulValues/i)
console.log(output)

you can do something like that (assuming array doesn't contain zero):
calculate product of all array elements
divide product by element at position [i] to get the desired output
const input = [1, 2, 3, 4, 5];
function output(items) {
const finalArray = [];
const multipliedNum=1;
for (let i = 0; i < items.length; i++) {
multipliedNum *= item[i];
}
for (let i = 0; i < items.length; i++) {
finalArray.push(multipliedNum/item[i]);
}
return finalArray;
}
console.log(output(input))

I know this has already been answered, but I think I have a better one.
If you take this issue by a different approach you will see that the product leaving the value at the index out, is also the product devided by value at the index.
If you know use the reduce function, you can simply calculate the product in one line using:
items.reduce((a, b) => a * b)
and then just divide by the value you want to ignore... like this:
items.reduce((a, b) => a * b) / items[index]
if you now want to compress this in one line instead of wrapping it into a for loop block you can simply copy the array and use the map function and the result could look like this:
result = [...items].map((v, i) => items.reduce((a, b) => a * b) / v)
I hope that this helps you to reduce your code

Related

Sum of similar value in n X n dimensional array with n^2 complexity

Given an array [[1, 7, 3, 8],[3, 2, 9, 4],[4, 3, 2, 1]],
how can I find the sum of its repeating elements? (In this case, the sum would be 10.)
Repeated values are - 1 two times, 3 three times, 2 two times, and 4 two times
So, 1 + 3 + 2 + 4 = 10
Need to solve this problem in the minimum time
There are multiple ways to solve this but time complexity is a major issue.
I try this with the recursion function
How can I optimize more
`
var uniqueArray = []
var sumArray = []
var sum = 0
function sumOfUniqueValue (num){
for(let i in num){
if(Array.isArray(num[i])){
sumOfUniqueValue(num[i])
}
else{
// if the first time any value will be there then push in a unique array
if(!uniqueArray.includes(num[i])){
uniqueArray.push(num[i])
}
// if the value repeats then check else condition
else{
// we will check that it is already added in sum or not
// so for record we will push the added value in sumArray so that it will added in sum only single time in case of the value repeat more then 2 times
if(!sumArray.includes(num[i])){
sumArray.push(num[i])
sum+=Number(num[i])
}
}
}
}
}
sumOfUniqueValue([[1, 7, 3, 8],[1, 2, 9, 4],[4, 3, 2, 7]])
console.log("Sum =",sum)
`
That's a real problem, I am just curious to solve this problem so that I can implement it in my project.
If you guys please mention the time it will take to complete in ms or ns then that would be really helpful, also how the solution will perform on big data set.
Thanks
I would probably use a hash table instead of an array search with .includes(x) instead...
And it's also possible to use a classical for loop instead of recursive to reduce call stack.
function sumOfUniqueValue2 (matrix) {
const matrixes = [matrix]
let sum = 0
let hashTable = {}
for (let i = 0; i < matrixes.length; i++) {
let matrix = matrixes[i]
for (let j = 0; j < matrix.length; j++) {
let x = matrix[j]
if (Array.isArray(x)) {
matrixes.push(x)
} else {
if (hashTable[x]) continue;
if (hashTable[x] === undefined) {
hashTable[x] = false;
continue;
}
hashTable[x] = true;
sum += x;
}
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
This is probably the fastest way...
But if i could choose a more cleaner solution that is easier to understand then i would have used flat + sort first, chances are that the built in javascript engine can optimize this routes instead of running in the javascript main thread.
function sumOfUniqueValue (matrix) {
const numbers = matrix.flat(Infinity).sort()
const len = numbers.length
let sum = 0
for (let i = 1; i < len; i++) {
if (numbers[i] === numbers[i - 1]) {
sum += numbers[i]
for (i++; i < len && numbers[i] === numbers[i - 1]; i++);
}
}
return sum
}
const sum = sumOfUniqueValue2([[1, 7, 3, 8],[[[[[3, 2, 9, 4]]]]],[[4, 3, 2, 1]]]) // 10
console.log("Sum =", sum)
You could use an objkect for keeping trak of seen values, like
seen[value] = undefined // value is not seen before
seen[value] = false // value is not counted/seen once
seen[value] = true // value is counted/seen more than once
For getting a value, you could take two nested loops and visit every value.
Finally return sum.
const
sumOfUniqueValue = (values, seen = {}) => {
let sum = 0;
for (const value of values) {
if (Array.isArray(value)) {
sum += sumOfUniqueValue(value, seen);
continue;
}
if (seen[value]) continue;
if (seen[value] === undefined) {
seen[value] = false;
continue;
}
seen[value] = true;
sum += value;
}
return sum;
},
sum = sumOfUniqueValue([[1, 7, 3, 8], [3, 2, 9, 4], [4, 3, 2, 1]]);
console.log(sum);
Alternatively take a filter and sum the values. (it could be more performat with omitting same calls.)
const
data = [[1, 7, 3, 8], [3, 2, 9, 4, 2], [4, 3, 2, 1]],
sum = data
.flat(Infinity)
.filter((v, i, a) => a.indexOf(v) !== a.lastIndexOf(v) && i === a.indexOf(v))
.reduce((a, b) => a + b, 0);
console.log(sum);
You can flatten the array, filter-out single-instance values, and sum the result:
const data = [
[ 1, 7, 3, 8 ],
[ 3, 2, 9, 4 ],
[ 4, 3, 2, 1 ]
];
const numbers = new Set( data.flat(Infinity).filter(
(value, index, arr) => arr.lastIndexOf(value) != index)
);
const sum = [ ...numbers ].reduce((a, b) => a + b, 0);
Another approach could be the check the first and last index of the number in a flattened array, deciding whether or not it ought to be added to the overall sum:
let sum = 0;
const numbers = data.flat(Infinity);
for ( let i = 0; i < numbers.length; i++ ) {
const first = numbers.indexOf( numbers[ i ] );
const last = numbers.lastIndexOf( numbers[ i ] );
if ( i == first && i != last ) {
sum = sum + numbers[ i ];
}
}
// Sum of numbers in set
console.log( sum );

How to compare two arrays and then return the sum of all elements of the array before the changed element of the array

I have two arrays that I need to check the difference upon and return the sum of all elements of the array before the changed element and includes him.
I currently have two arrays of area height that get updated when the input's value is changed. Also can be changed 2 or more elements of array, then need sum all changed elements and all elements before last changed element.
For example arrays:
let oldArea = [3, 4, 2]
let newArea = [3, 6, 2]
I tried something like this (it does its job partially, but the array length can be 5 or more elements, so this solution is bad) :
let oldArea = [3, 4, 2]
let newArea = [3, 6, 2]
let changedArea = [];
if (
oldArea[0] !== newArea[0] &&
oldArea[1] === newArea[1]
) {
changedArea.push(newArea[0]);
} else if (
oldArea[1] !== newArea[1] &&
oldArea[0] === newArea[0] &&
oldArea[2] === newArea[2]
) {
changedArea.push(newArea[0] + newArea[1]);
} else changedArea.push(newArea.reduce((a, b) => a + b, 0));
let changedAreaHeight = changedArea.reduce((a, b) => a + b, 0);
console.log(changedAreaHeight)
Example
I will be grateful for any tips with other solutions.
You can use a simple for loop and break when the elements are not same
let oldArea = [3, 4, 2]
let newArea = [3, 6, 2]
let final = 0;
for (let i = 0; i < newArea.length; i++) {
if (newArea[i] === oldArea[i]) {
final += newArea[i]
} else {
final += newArea[i]
break;
}
}
console.log(final)

How do I sum the elements of an arbitrary number of arrays with different lengths in Javascript?

While the code below will satisfy adding two arrays with different lengths, how can I modify this to accept an arbitrary number of arrays as arguments so that, for example, ([1, 2, 3], [4, 5], [6]) will return an array of [11, 7, 3] ?
const addTogether = (arr1, arr2) => {
let result = [];
for (let i = 0; i < Math.max(arr1.length, arr2.length); i++) {
result.push((arr1[i] || 0) + (arr2[i] || 0))
}
return result
}
Use a nested array, and loop over the array rather than hard-coding two array variables.
You can use arrays.map() to get all the lengths so you can calculate the maximum length. And arrays.reduce() to sum up an element in each array.
const addTogether = (...arrays) => {
let result = [];
let len = Math.max(...arrays.map(a => a.length));
for (let i = 0; i < len; i++) {
result.push(arrays.reduce((sum, arr) => sum + (arr[i] || 0), 0));
}
return result
}
console.log(addTogether([1, 2, 3], [4, 5], [6]));
You can use arguments object inside function.
arguments is an Array-like object accessible inside functions that contains the values of the arguments passed to that function.
const addTogether = function () {
const inputs = [...arguments];
const maxLen = Math.max(...inputs.map((item) => item.length));
const result = [];
for (let i = 0; i < maxLen; i ++) {
result.push(inputs.reduce((acc, cur) => acc + (cur[i] || 0), 0));
}
return result;
};
console.log(addTogether([1,2,3], [4,5], [6]));
Solution:
const addTogether = (...args) => {
let result = [];
let max = 0;
args.forEach((arg)=>{
max = Math.max(max,arg.length)
})
for(let j=0;j<max;j++){
result[j]= 0
for (let i = 0; i < args.length; i++) {
if(args[i][j])
result[j]+= args[i][j]
}
}
return result
}
console.log(addTogether([1, 2, 3], [4, 5], [6]))
Output:[ 11, 7, 3 ]
Use rest param syntax to accept an arbitrary number of arguments. Sort the outer array by their length in descending order. By using destructuring assignment separate the first and rest of the inner arrays. At last use Array.prototype.map() to traverse the first array as it is the largest array and use Array.prototype.reduce() method to get the summation.
const addTogether = (...ar) => {
ar.sort((x, y) => y.length - x.length);
const [first, ...br] = ar;
return first.map(
(x, i) => x + br.reduce((p, c) => (i < c.length ? c[i] + p : p), 0)
);
};
console.log(addTogether([1, 2, 3], [4, 5], [6]));
Instead of using a for loop that requires you to know the lengths of each array, try using something that doesn't. For example - while loop.
Increment using a dummy variable and reset it for each array and set condition for loop termination as - arr[i] === null.

Remove duplicates from sorted array and return length - Must mutate the original array

DISCLAIMER
I am well aware of the duplicate questions, however this one is asking to remove duplicates without making a new array and wants us to mutate the original array.
INSTRUCTIONS
Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
EXAMPLE
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the returned length.
ATTEMPT
const removeDuplicates = function(nums) {
for(let i of nums){
if(nums[i] === nums[i]){
nums.splice(i, 1)
}
}
return nums.length;
};
console.log(removeDuplicates([1, 1, 2]));
console.log(removeDuplicates([1, 2]));
// [1, 1, 2] => [1, 2] (Correct)
// [1, 2] => [1] (Incorrect - should be [1, 2])
Am I mutating the array correctly with splice and what do I need to do to correct the 2nd argument?
Also, in leetcode, when I run the first argument, it says it's correct and returns the array of the leftover elements, but the instructions were asking for the length of the new array. Not sure if I'm missing something but why is it not returning the length?
https://imgur.com/5cuhFYf
Here you are:
const removeDuplicates = function(nums) {
for(let i = 0; i < nums.length;){
if(nums[i] === nums[++i]){
nums.splice(i, 1)
}
}
return nums.length;
};
console.log(removeDuplicates([1, 1, 2]));
console.log(removeDuplicates([1, 2]));
let nums = [1,1,2];
nums = [...new Set(nums)].length;
console.log(nums);
nums = [1,1,2];
nums = nums.filter(function(item, pos, self) {
return self.indexOf(item) == pos;
})
console.log(nums)
For each element of the array you need to iterate through all remaining elements of that array, to check for all duplicates. Not sure if this is more performant then making a copy.
const removeDuplicates = function (nums) {
let i = 0;
while (i < nums.length) {
let j = i + 1;
while (j < nums.length) {
if (nums[i] === nums[j]) {
nums.splice(j, 1);
}
else {
j++;
}
}
i++;
}
return nums.length;
};
console.log(removeDuplicates([1, 1, 2]));
console.log(removeDuplicates([1, 2]));
console.log(removeDuplicates([1, 2, 1, 3, 4, 3, 2, 1]));
// [1, 1, 2] => [1, 2] (Correct)
// [1, 2] => [1] (Incorrect - should be [1, 2])
// [1, 2, 1, 3, 4, 3, 2, 1] => [1, 2, 3, 4]
The hint is in the line: It doesn't matter what you leave beyond the returned length.
Whoever is asking you this wants you to move through the array keeping track of 2 pointers: 1) The end of the output array and 2) the current index in the input array.
If you do this, and copy the input to the output pointer only when they're different, you will end up with the correct output, the correct length (from the output pointer) and a little bit of garbage at the end of the array.
const unique = (arr) => {
let output = 0;
for (let input = 0; input < arr.length; input++) {
if (arr[output] !== arr[input]) {
output++;
arr[output] = arr[input];
}
}
return output + 1;
}
const arr = [1, 1, 2, 3, 3, 3, 4, 5, 5, 6, 8, 8, 8, 9, 11];
const length = unique(arr);
console.log(arr, length);
I believe this solution will pass more test cases (at least in my personal testing)
const removeDups = (nums) => {
// since mutating arrays I like to start at the end of the array so when the index is removed it doesn't impact the loop
let i = nums.length - 1;
while(i > 0){
// --i decrements then evaluates (i.e 5 === 4), i-- decriments after the evaluation (i.e 5 === 5 then decrements the last 5 to 4)
if(nums[i] === nums[--i]){
// remove the current index (i=current index, 1=number of indexes to remove including itself)
nums.splice(i,1);
}
}
console.log(nums);
return nums.length;
};
// Test Cases
console.log(removeDups([1,1,2])); // 2
console.log(removeDups([0,0,1,1,1,2,2,3,3,4])); // 5
console.log(removeDups([0,0,0,2,3,3,4,4,5,5])); // 5
Tried the solution provided by Kosh above, but it failed for bigger array [0,0,1, 1, 1, 2, 2, 3, 3, 4]. So ended up writing my own. Seems to work for all tests.
var removeDuplicates = function(nums) {
var i;
for (i = 0; i <= nums.length; i++) {
const tempNum = nums[i];
var j;
var tempIndex = [];
for (j = i+1; j <= nums.length; j++) {
if (tempNum === nums[j]) {
tempIndex.push(j)
}
}
nums.splice(tempIndex[0], tempIndex.length)
}
return (nums.length);
};

How to sort an array of odd numbers in ascending order, but keep even numbers at their position?

I want to sort only odd numbers without moving even numbers. For example, when I write :
sortArray([5, 3, 2, 8, 1, 4])
The expected result is :
[1, 3, 2, 8, 5, 4]
I am new to JavaScript and I came across a challenge on the Internet that has me perplexed. I normally wouldn't post asking for a solution on the Internet, BUT I have tried for hours and I would like to learn this concept in JavaScript.
The challenge states :
You have an array of numbers.
Your task is to sort ascending odd numbers but even numbers must be on their places.
Zero isn't an odd number and you don't need to move it. If you have an empty array, you need to return it.
Here is my code so far, please take it easy on me I am in the beginning stages of programming.
function sortArray(array) {
let oddNums = [];
for(let i = 0; i < array.length; i++) {
if(array[i] % 2 !== 0) {
oddNums.push(array[i]);
}
}
oddNums = oddNums.sort((a,b)=> a-b);
array.concat(oddNums);
array = array.sort((a,b) => a-b);
return array;
}
You could take a helper array for the odd indices and another for the odd numbers, sort them and apply them back on the previously stored indices of the original array.
var array = [5, 3, 2, 8, 1, 4],
indices = [];
array
.filter((v, i) => v % 2 && indices.push(i))
.sort((a, b) => a - b)
.forEach((v, i) => array[indices[i]] = v);
console.log(array);
Here's a solution using mostly the built-in array methods. Get a list of just the odds, sort it, then map through the original, replacing each item with the first sorted odd if the item is odd, or itself if even:
const array = [5, 3, 2, 8, 1, 4] // to: [1, 3, 2, 8, 5, 4]
function sortOddsOnly(arr) {
const odds = arr
.filter(x => x%2)
.sort((a, b) => a - b);
return arr
.map(x => x%2 ? odds.shift() : x);
}
console.log(sortOddsOnly(array));
I have a solution like this.
Build a sorted odd number array 1st, and then fill the rest of even numbers in order:
const arr = [5, 3, 2, 8, 1, 4];
const odd = arr.filter(i => i%2 !== 0).sort();
let i = 0,
result = [];
arr.forEach(e => {
if (e%2 === 0) {
result.push(e)
} else {
result.push(odd[i]);
i++;
}
});
console.log(result);
just do:
arr.sort((a, b) => a%2 && b%2 ? a - b : 0)
If that works depends on the sort algorithm your browser uses.
A browserindependent version:
for(const [i1, v1] of arr.entries())
for(const [i2, v2] of arr.entries())
if( v1%2 && v2%2 && (i1 < i2) === (v1 > v2))
([arr[i1], arr[i2]] = [v2, v1]);
One of the possible solutions is this. What I have done is created new array odd(array with odd position in original array using Array.prototype.filter) and then sort that array using Array.prototype.sort. Then using Array.prototype.map change value of all odd element of original array with odd array.
x1=[5, 3, 2, 8, 1, 4];
function sortArray(array) {
var odd = array.filter((x,i) => (i+1) % 2 ).sort((a,b) => a > b); //sort odd position and store that in new array
return array.map((x,i) => (i+1) % 2 ? odd.shift() : x ); //if i is odd then replace it with element from
//odd array otherwise keep the element as it is
}
console.log(sortArray(x1));
Here is a possible solution using a slightly customized selection sort :
var xs = [5, 3, 2, 8, 1, 4];
console.log(sortOddsOnly(xs));
function sortOddsOnly (xs) {
var n = xs.length;
for (var i = 0; i < n - 1; i++) {
if (xs[i] % 2 === 1) {
for (var j = i + 1; j < n; j++) {
if (xs[j] % 2 === 1) {
if (xs[i] > xs[j]) {
var min = xs[j];
xs[j] = xs[i];
xs[i] = min;
}
}
}
}
}
return xs;
}
The first two if guarantee that we swap only odd numbers (x % 2 === 1 means "x is odd").
def sort_array(source_array):
b = sorted([n for n in source_array if n % 2 != 0])
c = -1
d = []
for i in source_array:
c = c+1
if i % 2 != 0 :
d.append(c)
for x in range (len(d)):
z = d[x]
source_array[z] = b[x]
return source_array

Categories

Resources