Looping multiple if statements based on array length - javascript

Just started learning javascript.
Input could be something like.
1, 5, 2, 7
and my task is to figure out how many numbers is missing between the lowest number and highest number.
var sorted = statues.sort();
var ticker = 0;
var plusser = sorted[0] + 1;
var plusser1 = sorted[1] + 1;
var plusser2 = sorted[2] + 1;
var plusser3 = sorted[3] + 1;
if(sorted[1] != plusser) {
ticker++
}
if(sorted[2] != plusser1) {
ticker ++;
}
if(sorted[3] != plusser2) {
ticker ++;
}
if(sorted[4] != plusser3) {
ticker ++;
}
this works great if there only is 4 numbers of input however, that ain't always the case and i am sure this can be coded cleaner if you use some sort of loop. Can you guys help me?

Find the max and min number and loop through array and check if a number is not part of array.
var arr = [1, 5, 2, 7];
var numberMissing = 0;
for(var i = Math.min.apply(Math, arr) + 1 ; i < Math.max.apply(Math, arr); ++i){
if(arr.indexOf(i) === -1){
console.log(i);
++numberMissing;
}
}
console.log("Missing Number : " + numberMissing);

task is to figure out how many numbers is missing between the lowest number and highest number
Sort the numbers : This will give the smallest number and largest number.
Subtract largest number and smallest number : This will give total numbers that could be included that range. Lets say this is N
Subtract Array Length with N : This will give number of missing number in the given array.
Since the question is to count and not to list all the missing numbers, we can take this approach. Following is the code example.
var input = [1,5,2,7];
var sortedInput = input.sort(); // this will work only for single digit array.
var firstNum = sortedInput[0],
lastNum = sortedInput[sortedInput.length-1],
numbersInRange = lastNum - firstNum +2; // +2 to include the numbers that are the range
var missingNumbers = numbersInRange - input.length;
console.log(missingNumbers)

If the array contains unique numbers (ie - 5 can't appear twice), you can use simple math:
var statues = [1, 5, 2, 7];
var result =
Math.max.apply(Math, statues) - Math.min.apply(Math, statues) + 1 // the amount of items that should be in the array
-
statues.length; // the current amount of items
console.log(result);
If you want the numbers as well, create a map of the existing numbers, and then create an array, that contain all numbers that don't exist in the initial array:
var statues = [1, 5, 2, 7];
function getMissingNumbers(arr) {
var result = [];
var map = arr.reduce(function(map, n) { // create a map of existing numbers
map[n] = true;
return map
}, {});
var max = Math.max.apply(Math, arr); // find the max
var min = Math.min.apply(Math, arr); // find the min
for(var i = min; i < max; i++) { // run from min to max
map[i] || result.push(i); // add only numbers that don't exist in the map
}
return result;
}
var result = getMissingNumbers(statues);
console.log('Missing items: ', result);
console.log('Number of missing items: ', result.length);

Here is a simple solution you can try :
var a = [1,5,2,7];
a.sort((a, b) => a-b)
.reduce((acc, element, index) => {
if(index) acc = acc + element - a[index-1] - 1; return acc;
}, 0);

Related

How to perform digit by digit multiplication in JS

I want to make a function which multiplies numbers digit by digit, like we did in school. For example, in 445 * 456, we first multiply 5 by 6, then, 4 and again 4. Then, we multiply 4 by 5 and so on. I want to do this for getting answers in strings for very very long multiplications.
Here, numArray is digits stored in array, e.g 563 is [5, 6, 3];
Similarily, another number can be e.g. 621 which is converted into [6, 2, 1]
for(var i = 1; i <= anotherNumArray.length; i++) {
var multiplier = anotherNumArray[anotherNumArray.length-i]
for(var j = 1; j <= numArray.length; j++) {
var multiplicand = numArray[numArray.length-j]
answer.unshift(multiplicand*multiplier);
}
I am trying to loop multiplication of numbers. But I am getting weird results.
the problem is more complicated than presented
assuming actual "long multiplication" simulation, i.e only digits multiplication and summation allowed, see below comments and working code.
first of all, the code is ignoring the fact that multiplications of two digits will overflow and will yield a non-zero carry value that should be summed with the next multiplication
secondly, as we've been tought in school, for each digit, we recieve a new multiplication result with all other digits of the second number. we will need to sum over those multiplication results in the end
code below works for non-negative decimal numbers. it could be simplified, but have tried to keep the spirit of the initial algorithm
// parameters
const lhs = "445";
const rhs = "456";
// utilities
const createZeros = length => new Array(length).fill(0);
const padArrayEnd = (length, padding, array) => [...array, ...createZeros(length - array.length)];
const last = array => array[array.length - 1];
// given a carray and an array of digits, add the carry to the last digit.
// if the result overflows, add the remainder as a new digit instead
// example;
// array = [3, 4, 5]; addCarry(2, array); array == [3, 4, 7]
// array = [3, 4, 9]; addCarry(2, array); array == [3, 4, 0, 1]
function addCarry(carry, digits) {
if (carry == 0) {
return;
}
let value = last(digits) + carry;
if (value > 10) {
digits[digits.length - 1] = 0;
digits.unshift(value % 10);
} else {
digits[digits.length - 1] = value;
}
}
console.log({ message: "start", lhs, rhs });
// state
const answer = [];
const entries = [];
let carry = 0;
// perform digit by digit multiplication.
// remember that the result array for each digit should have N leading zeros, where N is the position of that digit.
// this is the reason we keep an array of entries. each entry, is the result array corresponding to that digit
for(let lcur = 0; lcur < lhs.length; lcur++) {
const leftDigit = lhs[lhs.length - 1 - lcur];
// the multiplications entry
const multiplications = createZeros(lcur);
for(let rcur = 0; rcur < rhs.length; rcur++) {
const rightDigit = rhs[rhs.length - 1 - rcur];
// perform multiplication, but notice that in case of overflow we keep
// only the ones, and remember carry for next iteration
const times = (leftDigit * rightDigit) + carry;
const ones = times % 10;
carry = Math.floor(times / 10);
multiplications.unshift(ones);
console.log({ message: "step", expr: `${leftDigit} * ${rightDigit}`, times, ones, carry });
}
if (carry != 0){
multiplications.unshift(carry);
carry = 0;
}
// update entries
entries.push(multiplications);
console.log({ message: "entry", multiplications });
}
// add the final carry
addCarry(carry, last(entries));
console.log({ message: "entries", entries });
// sum all entries with carries
const maxLength = entries
.map(entry => entry.length)
.reduce((acc, entry) => Math.max(acc, entry), 0);
// for convinience, reverse all entries - this can by bypassed with messing around with indices
entries.forEach(entry => entry.reverse());
carry = 0;
for (let idx = 0; idx < maxLength; ++idx) {
const sum = entries
.map(entry => entry[idx] || 0)
.reduce((acc, value) => acc + value, carry);
const ones = sum % 10;
carry = Math.floor(sum / 10);
answer.unshift(ones);
console.log({ message: "summation", sum, ones, carry, answer });
}
// add final summation carry
// remember that we reversed stuff before, reverse back
// answer.reverse()
addCarry(carry, answer);
// finalize a result
const result = answer.join("");
const expected = (parseInt(lhs) * parseInt(rhs)).toString(); // string for some reason
console.log({ message: "finish", expr: `${lhs} * ${rhs} = ${answer.join("")}`, answer, expected });
If I understood your question correctly, you want an algorithm that multiplies two n-digit numbers using the Long multiplication method that most of us were taught in school.
Here is my approach (excessively commented so you understand what it does):
var n1 = [5, 6, 3]; // multiplicand
var n2 = [6, 2, 1]; // multiplier
var expectedResult = parseInt(n1.join('')) * parseInt(n2.join(''));
console.log('expectedResult = ' + expectedResult);
var partialProducts = [];
var product = '';
// Iterate over the multiplier from right to left
for (var i = n2.length - 1; i >= 0; i--) {
var d2 = n2[i];
var carry = 0;
// Iterate over the multiplicand from right to left
for (var j = n1.length - 1; j >= 0; j--) {
var d1 = n1[j];
// Perform the multiplication
var mult = (d2 * d1) + carry;
// Recalculate the carry for the next iteration
carry = Math.floor(mult / 10);
// add the last number of the multiplication
product = (mult % 10) + product;
}
// Add the remaining carry in case theres some left
product = (carry % 10) + product;
// Add a new product to the partialProducts array
// shifted the needed places to the left
var shift = (10 ** (n2.length - i - 1));
partialProducts.push(product * shift);
// A new product was pushed, clear it for the next iteration
product = '';
}
// Finally, just sumate all the partial products
var result = partialProducts.reduce((a, c) => a + c);
console.log('result = ' + result);

Find averages in an array of different numbers

I feel like I didn't phrase my title very well, can someone please correct it if you understand my question.
I have an array of
arr = [1,2,3,4,5,
6,7,8,9,0,
3,4,7,2,1,
4,6,1,2,3,
5,6,8,9,3
2,3,4,5,6
]
And I want to do several things
Split it into chunks with the size of 5
Calculate the number of chunks. In this case, it should be 6 chunks.
Calculate the sum of numbers of all chunks in each position and divide it by the total number of chunks. In this case,
(1+6+3+4+5+2)/6, (2+7+4+6+6+3)/6, ..., (5+0+1+3+3+6)/6
Return results as an array
var result = [3.5, 4.66, ..., 3]
I have got the idea, but not sure how to implement it.
Thanks
I believe this code accomplishes what you want.
function averageValues (arr) {
var chunks = Math.ceil(arr.length / 5); // find the number of chunks
var sums = [0, 0, 0, 0, 0]; // keep a running tally
for (var i = 0; i < arr.length; i ++) {
sums[i % 5] += arr[i]; // add each element to the proper part of the sum
}
for (var i = 0; i < sums.length; i ++) {
sums[i] /= chunks; // divide each part of the sum by the number of chunks
}
return sums;
}
You can solve this by maintaining five separate sums to end with five separate averages.
Prepare your sums array of length 5:
var sums = [ 0, 0, 0, 0, 0 ];
For each number in your set, increment the corresponding sum by that number.
for (var x = 0; x < arr.length; x++)
sums[x % 5] += arr[x];
Divide each sum by how many numbers were used:
var numbers = arr.length / 5; // 6 numbers each
var result = sums.map(
function(s) {
return s / numbers; // divide each sum by 6
}
);
This uses the assumption that your set length is always a multiple of 5.
Here is a more functional approach to your problem. This uses the assumption that your set length is always a multiple of 5.
// add extra array helpers
Array.prototype.eachSlice = function (n, fn) {
let slices = [];
for (let i = 0; i < this.length; i += n) {
let slice = this.slice(i, i + n);
slices.push(slice);
}
if (fn) slices.forEach(fn);
return slices;
}
Array.prototype.sum = function (fn) {
let fnReduce = fn ? (acc, ...args) => acc + fn(...args) : (acc, v) => acc + v;
return this.reduce(fnReduce, 0);
}
Array.prototype.avg = function (fn) {
return this.sum(fn) / this.length;
}
// actual solution
let arr = [
1,2,3,4,5,
6,7,8,9,0,
3,4,7,2,1,
4,6,1,2,3,
5,6,8,9,3,
2,3,4,5,6,
];
let chunkSize = 5;
console.log('--- question #1 ---');
console.log('Split it into chunks with the size of 5.');
console.log('-------------------');
let chunks = arr.eachSlice(chunkSize);
console.log(chunks);
console.log('--- question #2 ---');
console.log('Calculate the number of chunks. In this case, it should be 6 chunks.');
console.log('-------------------');
console.log(chunks.length);
console.log('--- question #3 ---');
console.log('Calculate the sum of numbers of all chunks in each position and divide it by the total number of chunks.');
console.log('-------------------');
let avgChunks = new Array(chunkSize).fill()
.map((_, i) => chunks.avg(chunk => chunk[i]));
console.log('See the result under question #4.');
console.log('--- question #4 ---');
console.log('Return results as an array.');
console.log('-------------------');
console.log(avgChunks);
It could be useful:
//The average method using an array
function average(arr) {
var sum = arr.reduce(function (a,b) { return a + b; },0)
return sum/ arr.length
}
//Chunk array method, it returns an array of the sliced arrays by size
function chunkArray(arr, chunkSize){
var numChunks = arr.length / chunkSize
var chunks= []
for (let index = 0; index < numChunks; index++) {
chunks.push(arr.slice(index * chunkSize, (index * chunkSize) + chunkSize))
}
return chunks
}
//Finally, the average of arrays, it returns the average of each array
function averageArrays(arrs){
return arrs.map(function (arr) {
return average(arr)
})
}
//Example of usage
var chunks = chunkArray([
1,2,3,4,5,
6,7,8,9,0,
3,4,7,2,1,
4,6,1,2,3,
5,6,8,9,3,
2,3,4,5,6
],5)
console.log(averageArrays(chunks))
I think #Aplet123 has the most straight forward and easy to understand approach, though I changed up a little bit to suit my needs.
var chunks = Math.ceil(arr.length / 5) // Find the number of chunks
var sums = new Array(5).fill(0) // Keeps a running tally and fill values 0
arr.map((x, i) => sums[i%5] += arr[i]) // add each element to the proper part of the sum
var avgs = sums.map((x) => x/chunks /divide each part of the sum by the number of chunks

looping infinitely through multiple arrays at the same time until a condition is met

I'm trying to find least common multiples of the two numbers given [3,5] and return only the number that's divisible by all the number in the range of the two numbers... for example:
The given array of two numbers --> let arr = [3,5];
The first number Multiples should be as follow:
[3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60];
The second number Multiples should be as follow:
[5,10,15,20,25,30,35,40,45,50,55,60];
The Least common multiples should be as follows:
[15,30,45,60];
the only that is divisible by all the number in the range is 60.
This is my approach to solve this problem but I want to know what's wrong with my code below (PLEASE EXPLAIN 'cause I'm tired of guessing):
let arr = [3, 5];
let arrRange = []; // [3, 4, 5]
// creating a loop to create the range
for (var i = arr[0]; i <= arr[1]; i++) {
arrRange.push(i);
}
let f = arr[0], s = arr[1], c = 0, result = 0, firstMultiples = [], secondMultiples = [], leastCommonMultiples = [];
// This function is made if the number least Common number is divisible by all the numbers in the "arrRange"
function isDivisible(num) {
for(var i = 0; i < arrRange.length; i++) {
if(num % arrRange[i] != 0) {
return false;
}
}
return true;
}
while(true) {
firstMultiples.push(f);
secondMultiples.push(s);
f = f + arr[0];
s = s + arr[1];
let vals = secondMultiples.values();
for(let val of vals){
if( firstMultiples.includes(val) ) {
leastCommonMultiples.push(val);
}
}
let cmlVals = leastCommonMultiples.values();
for(let cmlVal of cmlVals){
if(isDivisible(cmlVal)) {
result += cmlVal;
break;
}
}
c++;
}
console.log(result);
To fix it, change the while-loop from while (true) {/*code*/}; to
while(isDivisible(cmlVal) == true) {/*code*/}; and remove the
if(isDivisible(cmlVal)) {/*code*/ break;}.

Number that represents the unique index of many arrays

I have an application that takes in multiple arrays of data each or variable length. I plan on cycling through and displaying every combination of data for each array I'm given. My first inclination was to have a single number represent the state of each array since I know the number of combinations is the product of the number of elements of each array.
So for example:
A = [0,1,2,3]
B = [0,1,2,3]
C = [0,1]
So 4 x 4 x 2 = 32 combinations I need to represent
I've managed to represent all states by applying modulo and division to a given index using each array.length. My problem is that it doesn't order well (see snippet below). Has anyone solved a similar problem or know how I could change the algorithm to get it in order?
function multiArrayIndex(index, ...args) {
var arrays = args.slice();
var output = [];
for (var i = 0, curIndex = index; i < arrays.length; i++) {
var curArray = arrays[i];
var valueIndex =(curIndex % curArray.length);
output.push(curArray[valueIndex]);
curIndex = Math.ceil(curIndex / curArray.length);
}
return output;
}
demoP = document.getElementById("demo");
for(var i = 32; i>=1; i--){
demoP.innerHTML = demoP.innerHTML + i + " - " + multiArrayIndex(i, [0,1,2,3], [0,1,2,3], [0,1] ) + "<br />";
}
<p id="demo"></p>
Keeping the indices separate would be a nicer approach in my opinion.
Incrementing the indices could work kinda similar to how we added two numbers by hand in elementary school - if an index is too large, set it to zero and increment the next one by one:
var a = [0, 1, 2, 3]
var b = [0, 1, 2, 3]
var c = [0, 1]
var state = {
a: 0,
b: 0,
c: 0
}
function increment() {
state.a++;
if (state.a >= a.length) {
state.b++;
state.a = 0;
}
if (state.b >= b.length) {
state.c++;
state.b = 0;
}
if (state.c >= c.length) {
state.c = 0;
}
console.log(state);
}
console.log(state);
<button onclick='increment()'>Increment</button>
Updating the document based on the state should be trivial from here.

Implementing merge sort iteratively

I'm trying to implement merge sort in order to get a better understanding of how it works. In the following code I am attempting to sort an array of numbers. The code I currently have is buggy and runs in an infinite loop. I'm trying to solve this non-recursively for now:
function mergeSort(arr) {
var mid = Math.floor(arr.length/2);
var left = arr.slice(0, mid);
var right = arr.slice(mid, arr.length);
if (arr.length === 1) {return arr};
var sorted = [];
var i = 0;
while (left.length || right.length) {
if (left.length && right.length) {
if (left[0] < right[0]) {
sorted.push(left.shift())
} else {
sorted.push(right.shift())
}
} else if (left) {
sorted.push(left.shift())
} else {
sorted.push(right.shift())
}
i++;
}
return sorted;
}
So if I have an array var nums = [1, 4, 10, 2, 9, 3]; calling mergeSort(nums) should return [1, 2, 3, 4, 9, 10].
You've written code that splits an array in two and merges the halves. This doesn't result in a sorted array because the two halves are not sorted. Mergesort works by sorting the two halves, then merging them.
There are many ways to implement mergesort iteratively. Let me offer one. Start by merging subarrays of size 1. You know that an array of size 1 is already sorted, so it's safe to merge two consecutive subarrays of size 1. If you do this to all consecutive pairs of subarrays of size 1 in the original array, you end up with an array consisting of consecutive sorted subarrays of size 2.
Do you see where this is going? Now you can merge every two consecutive subarrays of size 2. You end up with an array of consecutive sorted subarrays of size 4. Keep on repeating this procedure until the whole array is sorted.
The following snippet implements this approach.
function mergeSort(arr) {
var sorted = arr.slice(),
n = sorted.length,
buffer = new Array(n);
for (var size = 1; size < n; size *= 2) {
for (var leftStart = 0; leftStart < n; leftStart += 2*size) {
var left = leftStart,
right = Math.min(left + size, n),
leftLimit = right,
rightLimit = Math.min(right + size, n),
i = left;
while (left < leftLimit && right < rightLimit) {
if (sorted[left] <= sorted[right]) {
buffer[i++] = sorted[left++];
} else {
buffer[i++] = sorted[right++];
}
}
while (left < leftLimit) {
buffer[i++] = sorted[left++];
}
while (right < rightLimit) {
buffer[i++] = sorted[right++];
}
}
var temp = sorted,
sorted = buffer,
buffer = temp;
}
return sorted;
}
function print(s) {
document.write(s + '<br />');
}
var data = [1, 4, 10, 2, 9, 3];
print('input: ' + data.join(', '));
print('output: ' + mergeSort(data).join(', '));

Categories

Resources