Max Average For All Durations - javascript

I want to find all possible maximum contiguous subarray averages from an array of values. Each array value represents the value at a duration, the number of seconds passed.
Ex. Input = [6, 4, 3, 10, 5]
Ex. Output = [5.6, 5.75, 6, 7.5, 10]
Output[0] = 6+4+3+10+5 / 5 = 5.6
Output[1] = 6+4+3+10 / 4 = 5.75
Output[2] = 3+10+5 / 3 = 6
Output[3] = 10+5 / 2 = 7.5
Output[4] = 10 / 1 = 10
The issue is that the real data has length of up to 40,000 values.
The result should have the same length as the input. I‘ve done a reduce on a subarray of specific lengths (only getting 5s, 60s, 3600s, etc. length), but that’s not a viable solution for each possible duration. Is there a way I can partition or otherwise create a specialized data structure to get these values? If not, how can I exclude durations as I go?

You can just take the reverse of the input array, then calculate sum and average incrementally. Then again taking the of output array.
const input = [6, 4, 3, 10, 5].reverse();
let output = [];
let total_sum = 0;
for (var i = 0; i < input.length; i++) {
total_sum += input[i];
let avg = total_sum / (i + 1);
output.push(avg);
}
console.log(output.reverse());
(You can even eliminate the reverse by looping the for loop in reverse order.)

Why not .map()? Mixed with reduce you could do something like this:
const output = [
[1, 2, 3, 4],
[5, 6, 7, 8]
];
const averages = output.map(
subarray =>
subarray.reduce(
(previousValue, currentValue) => previousValue + currentValue,
0
) / subarray.length
);
Where subarray is the collection of values, they're then added together and divided by the length of the subarray.
I hope this is what you mean

Related

How to sum numbers in array by index in javascript

I have an array
const array = [6,2,6,7,5,9];
I want sum of all numbers till 7 in array
I tried .reduce but it gave me sum of whole array,
How can I do that so?
You're going to have to jump through a lot of hoops with reduce. You'd need to find the index of 7, then splice up to that index, and then reduce over the spliced array. Muy complicado!
It's much simpler to create a sum variable, and loop over the array. Add each number to the sum, and when the number is 7 break the loop.
It's worth noting this strategy wouldn't work for duplicate numbers like 6 for example because which 6 would you choose?
const arr = [6, 2, 6, 7, 5, 9];
let sum = 0;
for (const n of arr) {
sum += n;
if (n === 7) break;
}
console.log(sum);
This is doable with just a for loop:
const array = [6, 2, 6, 7, 5, 9];
let sum = 0;
for (let i = 0; i < array.length; i++) {
sum += array[i];
if (array[i] == 7) break;
}
// outputs the sum of [6,2,6,7], which is 21
console.log(sum);
Here we take the sum of numbers till 7 to mean the sum of all numbers in our array up until the first instance of 7.
Try using this. This is going to loop trow and store the sum until it's 7.
const array = [6, 2, 6, 7, 5, 9]
let sum = 0
array.forEach((number) => {
if (sum <= 7) sum += number
})
console.log(sum) // Output: 8
Do write the following code before you reduce it!
const arr1 = array.slice(0,4);
and then reduce arr1. you will get your desired Answer!
oh and please change the name of the constant however you want!
Here you go,
const array = [6, 2, 6, 7, 5, 9];
const found = array.find(element => element >= 7);
const newArr = array.indexOf(found);
const arr1 = array.slice(0,(newArr + 1));
const sum = 0;
const result = arr1.reduce(
(previousValue, currentValue) => previousValue + currentValue,
sum
);
console.log(result); //output 21

Converting an array of digits into a number for large numbers ignores some digits

I am converting array digits into a number e.g. [1,2,4] = 124.
This code is working for smaller values but when I checked for big values like [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3], I was not able to add the last 543 to my sum.
var plusOne = function(digits) {
let tsum = 0;
let sum = 0;
for (let i = 0; i < digits.length; i++) {
let k =Math.pow(10, (digits.length - (i + 1)));
tsum = arr[i]* k;
console.log(tsum);
sum = sum + tsum;
console.log(sum);
}
console.log(sum);
sum= sum + 1;
let cnt=0;
while (sum!=0) {
digits.unshift(Math.floor(sum%10));
sum = Math.floor(sum/10);
cnt++;
}
digits.length = cnt;
return digits;
};
let arr = [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3];
console.log(plusOne(arr));
First, join the digits and make a string:
const joined =[6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3].join('')
// output: "6145390195186705543"
Second, convert the string to a BigInt:
const number = BigInt(joined)
Your method for adding a one to a an array of digits won’t work for large numbers. JavaScript stores all numbers as a floating point, so as Darshna Rehka and pesehr suggested, you should use BigInt for this. See Issue with combining large array of numbers into one single number
for more information.
Although this doesn’t directly answer your question, here’s a different implementation of plusOne that should work for larger numbers:
const plusOne = digits => {
// Base case: treat empty arrays as 0 so return [1]
// This part is important for the recursion below
if (!digits.length) return [1];
const init = digits.slice(0, -1);
const last = digits[digits.length - 1];
return last === 9
// 9 + 1 = 10, carry the 1 (add 1 to the rest of the digits)
// If there are no more digits to the left of the 9 (init.length === 0),
// plusOne(init) will just return [1] (base case)
? [...plusOne(init), 0]
// Simply add 1 to the last digit and keep the rest
: [...init, last + 1];
};
const arr = [6, 1, 4, 5, 3, 9, 0, 1, 9, 5, 1, 8, 6, 7, 0, 5, 5, 4, 3];
console.log(plusOne(arr).join(''));
console.log(plusOne([1, 8, 9]).join(''));
console.log(plusOne([9, 9, 9]).join(''));

Unshuffle JavaScript array

I have a huge array of data that I got from PDF files. The pdfs had 10 data items per page but because it was presented in two columns the data is shuffled. The first and last item of each group of ten items are in the correct position but the rest are not.
The order is now 0,2,4,6,8,1,3,5,7,9,10,12,14,16,18,11...
and i need it to be 0,1,2,3...
I've tried looping through the array and pushing items to a new array using different if statements but just cant get it right.
Here is a function that takes the data as you get it, and two more arguments to indicate the number of columns and number of rows on a page:
function uncolumnize(data, numColumns, numRows) {
let perPage = numColumns * numRows;
return data.map((_, i) =>
data[Math.floor(i / perPage) * perPage
+ Math.floor((i % perPage) / numColumns)
+ (i % numColumns) * numRows]
);
}
let res = uncolumnize([0,2,4,6,8,1,3,5,7,9,10,12,14,16,18,11,13,15,17,19], 2, 5);
console.log(res);
It uses the map Array method, since the result (obviously) has just as many elements as the original data. The callback given to map does not use the value, but only the index. That index is used to determine the page, the row and the column. The latter two are reversed to rebuild a new index, and the data at that new index is returned.
2 columns of 10 elements per page will have groups of 10 as 10n,10n+2,10n+4,10n+6,10n+8,10n+1,10n+3,10n+5,10n+7,10n+9
There will be groups of 10 elements and one group (the last one) which will have 0-9 elements.
N = 5 //numbers of rows
len = numbers.length //numbers is the array
groups_of_2n_len = len/(2*N)
last_group_len = len%(2*N)
//For each group complete group
for(group_i = 0; group_i<groups_of_2n_len ; group_i=group_i +1)
{
//Store those 2N elements in an array
temp_array = numbers.slice(group_i*2*N,group_i*2*N + 2*N)
element = group_i*2*N
//Iterate row wise and fix the numbers
for(temp_i = 0; temp_i< N; temp_i = temp_i+1)
{
numbers[element]=temp_array[temp_i]
numbers[element+1] = temp_array[temp_i + N]
element = element+2
}
}
//For last group
if(last_group_len ==0) return
temp_array = numbers.slice(groups_of_2n_len*2*N,/*Till Last element*/)
element = groups_of_2n_len*2*N
for(temp_i = 0; temp_i< floor(last_group_len/2); temp_i = temp_i+1)
{
numbers[element]=temp_array[temp_i]
numbers[element+1] = temp_array[temp_i + floor(last_group_len/2)+last_group_len%2]
element = element+2
}
//In case of odd number of elements, no need to handle
//last element since it is already in correct place
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Example highlighted:
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
return a - b;
});
console.log(numbers);
// [1, 2, 3, 4, 5]
If numbers are in two separate arrays you can do something like this...
const array1 = [0, 4, 6, 5, 7];
const array2 = [1, 3, 2, 8, 9];
const combined = [...array1, ...array2];
console.log(combined);

JavaScript: Rearrange an array in order – largest, smallest, 2nd largest, 2nd smallest, 3rd largest, 3rd smallest,

Given an array of integers, where the values should be sorted in the following order:
if we have an array
[1, -1, -3, 9, -2, -5, 4, 8,]
we must rearrange it this way: largest number, smallest number, 2nd largest number, 2nd smallest number, ...
[9, -5, 8, -3, 4, -2, 1, -1 ]
I get the first largest and smallest numbers, but can't figure out how to make it dynamic for all values in the array.
I know that I must take two variables, say firstSmallest and firstLargest and point them to the first and last index of the array respectively, run a loop, which I do already in the code below, and store value into new array by incrementing firstSmallest and decrementing firstLargest, but couldn't implement into code.
let unsortedArr = [1, 5, 8 , 7, 6, -1, -5, 4, 9, 5]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => a-b);
let firstSmallest = sorted[0];
let firstLargest = sorted[unsorted.length-1];
for(let i = 0; i <= sorted.length; i++){
//I should increment firstSmallest and decrement firstLargest numbers and store in output
}
return output;
}
meanderArray(unsortedArr);
console.log(output);
You could take a toggle object which takes the property of either the first item or last from an array and iterate until no more items are available.
function meanderArray([...array]) {
const
result = [],
toggle = { shift: 'pop', pop: 'shift' };
let fn = 'shift';
array.sort((a, b) => a - b);
while (array.length) result.push(array[fn = toggle[fn]]());
return result;
}
console.log(...meanderArray([1, 5, 8, 7, 6, -1, -5, 4, 9, 5]));
You can sort an array by descending, then logic is the following: take first from start and first from end, then second from start-second from end, etc.
let unsortedArr = [1, 5, 8 , 7, 6, -1, -5, 4, 9, 5]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => b-a);
let output = []
for(let i = 0; i < sorted.length/2; i++){
output.push(sorted[i])
if(i !== sorted.length - 1 - i){
output.push(sorted[sorted.length - 1 - i])
}
}
return output;
}
let result = meanderArray(unsortedArr);
console.log(result);
You can sort, then loop and extract the last number with pop() and extract the first number with shift().
let unsortedArr = [1, -1, -3, 9, -2, -5, 4, 8,]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => a - b);
for(let i = 0; i < unsortedArr.length + 2; i++){
output.push(sorted.pop());
output.push(sorted.shift());
}
console.log(output);
return output;
}
meanderArray(unsortedArr);
Fastest Meandering Array method among all solutions mentioned above.
According to the JSBench.me, this solution is the fastest and for your reference i have attached a screenshot below.
I got a different approach, but i found that was very close to one of above answers from elvira.genkel.
In my solution for Meandering Array, First I sorted the given array and then i tried to find the middle of the array. After that i divided sorted array in to two arrays, which are indices from 0 to middle index and other one is from middle index to full length of sorted array.
We need to make sure that first half of array's length is greater than the second array. Other wise when applying for() loop as next step newly created array will contains some undefined values. For avoiding this issue i have incremented first array length by one.
So, always it should be firstArr.length > secondArr.length.
And planned to create new array with values in meandering order. As next step I created for() loop and try to push values from beginning of the first array and from end of the second array. Make sure that dynamically created index of second array will receive only zero or positive index. Other wise you can find undefined values inside newly created Meandering Array.
Hope this solution will be helpful for everyone, who loves to do high performance coding :)
Your comments and suggestions are welcome.
const unsorted = [1, 5, 8, 7, 6, -1, -5, 4, 9, 5];
const sorted = unsorted.sort((a,b)=>a-b).reverse();
const half = Math.round(Math.floor(sorted.length/2)) + 1;
const leftArr = sorted.slice(0, half);
const rightArr = sorted.slice(half, sorted.length);
const newArr = [];
for(let i=0; i<leftArr.length; i++) {
newArr.push(leftArr[i]);
if (rightArr.length-1-i >= 0) {
newArr.push(rightArr[rightArr.length-1-i]);
}
}

using reduce inside a for loop make the code O(n) complexity or higher like O(n^2) or another kind?

For an interview, they ask me to do some exercises and the 3rd one was the following:
We have an unknown quantity of elements in a vector/array v1 with random integer numbers.
Made a v2 vector/array with the same length of v1 in that the v2[k] is the product of all the elements of v1 except v1[k]
try to do it without the division operator and with complexity O(n).
And I do the following code:
const v1 = [4, 2, 7, 8, 6, 7, 9, 3, 2, 6, 7]; //it's just an example array
const l = v1.length;
let v2 = [];
for (let i = 0; i < l; i++) {
let segment = v1.splice(0, 1); // save the number of the position in array that it'll exclude de product
let product = v1.reduce((total, number) => { return total * number; }, 1);
v2.push(product); // add the result to the v2 array at the position of the number of v1 array
v1.push(segment); // is necesary to add again the segment of the v1 array to keep the original length
}
console.log('v2', v2);
/* Results Reference
product of all array 42674688
product - position 00 10668672
product - position 01 21337344
product - position 02 6096384
product - position 03 5334336
product - position 04 7112448
product - position 05 6096384
product - position 06 4741632
product - position 07 14224896
product - position 08 21337344
product - position 09 7112448
product - position 10 6096384
*/
My question is:
Is my code an O(n) complexity? or is O(n^2)? or another kind of complexity?
thanks
Your code is not O(n) because for each element of array v1, you run the .reduce() function that runs through the whole array, so it's O(n^2).
You can do it by calculating the total product, then iterating once through the v1 array and pushing the total / current to the v2 array. That way you will have the desired result with O(n) complexity.
const v1 = [4, 2, 7, 8, 6, 7, 9, 3, 2, 6, 7];
const v2 = [];
const productTotal = v1.reduce((res, curr) => res * curr);
v1.forEach((el) => v2.push(productTotal/el));
console.log(v2);
So in total you iterate twice through the v1 array - once to calculate productTotal and once to calculate v2, so in fact, that's a O(2n) complexity, but we can ignore the 2 because it's still O(n).
To achieve it without division you could use a trick, and instead of using division directly, you could use multiplication and the power of -1 (don't know if that counts):
const v1 = [4, 2, 7, 8, 6, 7, 9, 3, 2, 6, 7];
const v2 = [];
const productTotal = v1.reduce((res, curr) => res * curr);
v1.forEach((el) => v2.push(productTotal*Math.pow(el, -1)));
console.log(v2);
As already answered by #Sebastian Kaczmarek, the time complexity of your code is O(n^2) since the time complexity of .reduce is O(n) and .reduce is in the for loop which runs through the whole array.
One possible solution of which time complexity is O(n) and does not use division operator is the following:
const v1 = [4, 2, 7, 8, 6, 7, 9, 3, 2, 6, 7];
const length = v1.length;
const v2 = new Array(length);
const listOfAccFromStart = new Array(length);
const listOfAccFromEnd = new Array(length);
let accFromStart = 1;
for (let i = 0; i < length; i++) {
accFromStart *= v1[i];
listOfAccFromStart[i] = accFromStart;
}
let accFromEnd = 1;
for (let i = length - 1; i >= 0; i--) {
accFromEnd *= v1[i];
listOfAccFromEnd[i] = accFromEnd;
}
v2[0] = listOfAccFromEnd[1];
v2[length - 1] = listOfAccFromStart[length - 2];
for (let i = 1; i < length - 1; i++) {
v2[i] = listOfAccFromStart[i - 1] * listOfAccFromEnd[i + 1];
}
console.log('v2', v2);
It saves the accumulated product values from start to listOfAccFromStart and the accumulated product values from end to listOfAccFromEnd. And it uses the saved values to set v2. Its time complexity is O(n) and its space complexity is O(n).

Categories