generating intervals multiples of 10 between two numbers - javascript

I have two numbers like ESP1 and ESP2.
In my DB there are many data to the ESP1 & ESP2, ESP1 is minimum values and ESP2 is maximum value.
i need to generate intervals between those two number in multiplies of 10, for example.
ESP1 = 0 and ESP2 = 83
my result should be [0,10,20,30,40,50,60,70,80].
how to write code for this in js

Just use a for loop:
function generateIntervalsOf(interval, start, end) {
const result = [];
let current = start;
while (current < end) {
result.push(current);
current += interval;
}
return result;
}
generateIntervalsOf(10, 0, 83) // [0, 10, 20, 30, 40, 50, 60, 70, 80]

Another solution
const a = 0;
const b = 83;
const result = _.range(a, b, 1).filter(item => item%10 == 0);
console.log(result)

Use either a for or while loop. There are two approaches you could take.
A: Brute force. Count up from the start number to the end number and store every multiple of ten.
const results = [];
for (let i = ESP1; i <= ESP2; i++) {
if (i %10 === 0) {
results.push(i);
}
}
B: Cleverness. Brute force might be slow if you were doing this over a very large range. Instead of going through every single number, we only need the multiples of ten. So, in short, we just need the next multiple of ten after ESP1, and we add ten until we exceed ESP2.
e.g.
const results = [];
const floor = ESP1 + 10 - ESP1 % 10;
// i.e. if ESP1 is 13, add 10 to get 23, and then subtract 3 to get 20
for(let i = floor; i < ESP2; i+= 10) {
results.push(i);
}
If we ran this with ESP1 = 3 and ESP2 = 56, we would get the result [10, 20, 30, 40, 50]. This approach will go through 1/10 as many iterations as approach A, since we're counting by tens.

Related

Divide a number into equal values and push to an array

I need to divide a number equally and push the values on the array. I'm using 100 as an example,
but when I do it, it goes [28, 24, 24, 24], and I need it to be [25, 25, 25, 25]
const divide = () => {
var number = 100
var n = 4
var values = []
while(number > 0 && n > 0){
var a = Math.floor(number / n / 4) * 4
number -= a
n--
values.push(a)
}
console.log(values)
}
If I understand your question correctly:
const divide = (num = 100, n = 4) => new Array(n).fill(num / n);
The Math.floor() function returns the largest integer less than or equal to a given number, in your code this functions make the result incorrect
this is a correct code :
const divide = () => {
var number = 100
var n = 4
var values = []
for(int i=1;i<=4;i++){
values.push(a/4)
}
console.log(values)
}
Here is another version of doing it:
const divide = (num = 100, n = 4) => {
const f=Math.floor(num/n);
return [...Array(n)].map((_,i)=>i-n+1?f:num-i*f);
}
console.log(divide());
console.log(divide(100,3));
You have couple of issues in your code, decreasing the n means that the next loop the divided value will change.
Here is an updated version that works correctly:
const divide = (number = 100, n = 4) => {
const values = [];
let times = n;
while(times > 0){
values.push(Math.floor(number / n));
times--;
}
return values;
}
console.log(divide());
To explain how this should work, in order to get the same number in the arrays nth times, n should not be changed.
So we are copying its value to a local variable that is hten used to create / control the loop.
Each time the loop runs we divide the target number with n - for all of the iterations so we get the same number and its always 1/4 of the 100.
Hope this helps ..

why JavaScript is behaving differently

why it is showing me 36 even though the minimum number is 27
var combination = [27, 36]
for (let x in combination) {
if (combination[x] < 50) {
var min = Math.min(combination[x])
}
}
console.log(min)
i tried this multiple ways like
var combination = [27, 30, 40, 44, 3, 239, 329, 2, 5, 20923, 96]
for (let x in combination) {
if (combination[x] < 50) {
var min = Math.min(combination[x])
}
}
console.log(min) //output-- 5 //it should be 2
in this third example i add (-) to 2
var combination = [27, 30, 40, 44, 3, 239, 329, -2, 5, 20923, 96]
for (let x in combination) {
if (combination[x] < 50) {
var min = Math.min(combination[x])
}
}
console.log(min) // output-- still 5 // it should be -2
again when am adding (-) to other numbers like in -96 or -5 the output was okay (-96) but when im adding (-) to 2 it is not showing me -2 in the output instead it showing me 5
not only in javascript i tried this with lua, php but output was same as js
can anyone explain me why this happen and how solve this
You're not comparing values to determine the minimum, but instead just replacing the min variable with the last number in the array that is smaller than 50. This can be fixed as follows:
let min = undefined;
for (let x in combination) {
if (combination[x] < 50) {
min = min == undefined ? combination[x] : Math.min(min, combination[x])
}
}
Using filter and reduce, this can be made a lot shorter:
combination.filter(x => x < 50).reduce((x, y) => Math.min(x, y))

Calculate mean max value per timeframe of array

I have an array of data that is recorded by a sensor at 1 second time intervals. I am trying to calculate the max mean value for each time interval for the recorded data. If I have 2 hours worth of data, I want to calculate the max mean value for 1 second intervals, 2 second intervals, 3 second intervals etc... all the way up to 2 hours.
For example, given the following 3 values:
[8, 14, 11]
I want to return the following:
[
{
"Interval": 1,
"MeanMax": 14,
},
{
"Interval": 2,
"MeanMax": 12.5,
},
{
"Interval": 3,
"MeanMax": 11,
}
]
I have created the following function which is returning the correct value but it is very slow from a performance perspective. It takes approx 30 seconds to calculate the output for a 2 hour block of data.
It is calculating all possible mean values for the given interval and then returning the largest.
let sampleData = Array.from({length: 20}, () => Math.floor(Math.random() * 20));
console.log("SampleData: " + sampleData)
let meanMaxByTimeFrame = [];
for(var intervalInSeconds = 1; intervalInSeconds <= sampleData.length; intervalInSeconds++){
let allAveragesForCurrentInterval = [];
for(var sampleDataIndex = 0; sampleDataIndex < sampleData.length; sampleDataIndex++){
if((sampleDataIndex + intervalInSeconds) > sampleData.length){
break;
}
let sum = sampleData.slice(sampleDataIndex, sampleDataIndex + intervalInSeconds).reduce((a, b) => a + b, 0);
let avg = sum/intervalInSeconds;
allAveragesForCurrentInterval.push(avg);
}
meanMaxByTimeFrame.push({'Interval': intervalInSeconds, 'MeanMax': Math.max.apply(Math, allAveragesForCurrentInterval)});
}
console.log(meanMaxByTimeFrame)
Any help would be much appreciated
Good old imperative code will do.
That, and using a windowing technique.
That is: we only need to scan the array once, for each window size:
[ 1, 2, 3, 4]
The sum of the first 3 elements is 6:
[ 1, 2, 3, 4]
--------
The next sum is 6 - 1 (the element that goes out) + 4 (the element that goes in).
[ 1, 2, 3, 4]
--------
So we keep the sum and divide by the window size to get the averages.
A full solution:
console.time();
function maxOfAverages(source, windowSize) {
if (windowSize > source.length || windowSize < 1) return null;
let sum = 0,
idx = 0;
while (idx < windowSize) sum += source[idx++];
let maxOfAverages = sum / windowSize;
while (idx < source.length) {
sum = sum - source[idx - windowSize] + source[idx];
const avg = sum / windowSize;
if (avg > maxOfAverages) maxOfAverages = avg;
idx++;
}
return maxOfAverages;
}
let sampleData = Array.from({ length: 2000 }, () =>
Math.floor(Math.random() * 20)
);
console.log("SampleData: " + sampleData);
let meanMaxByTimeFrame = [];
for (let interval = 1; interval <= sampleData.length; interval++) {
const meanMax = maxOfAverages(sampleData, interval);
meanMaxByTimeFrame.push({ Interval: interval, MeanMax: meanMax });
}
console.timeEnd();
console.log(meanMaxByTimeFrame);
Disclaimer: this technique doesn't cope well with vastly different values. E.g., if there are more than 15 orders of magnitude of difference between minimum and maximum values, rounding errors are going to creep up in the sum. So, if you have lots of digits and very different numbers, you could want to recalculate the sum every time. Still, use while/for loops and leave the functional stuff to every non critical part of the application.
First you should not allways recalculate the upper-border from the loops. You could store these values before. But this will help you only a bit.
Second you allways recalculate the sum although you have done this without adding the last value before. In order to avoid this I store the sum in an new sumArray so I had only to add one and not all values. At the start with intervalInSeconds=1 I haven't any sum from before so I add instead nothing.
With this solution I could reduce the time e.g. for 1000 intervalls from 3100 ms to only 90 ms.
let sampleData = Array.from({length: 100}, () => Math.floor(Math.random() * 20));
console.log("SampleData: " + sampleData)
let meanMaxByTimeFrame = [];
let start = performance.now();
let sampleDataLength = sampleData.length;
let sampleDataMaxIndex = sampleDataLength;
let sumArray = [];
for(var intervalInSeconds = 1; intervalInSeconds <= sampleDataLength; intervalInSeconds++){
let allAveragesForCurrentInterval = [];
for(var sampleDataIndex = 0; sampleDataIndex < sampleDataMaxIndex; sampleDataIndex++){
sumArray[sampleDataIndex] = sampleData[sampleDataIndex+intervalInSeconds-1] + ((intervalInSeconds === 1) ? 0 : sumArray[sampleDataIndex]);
let avg = sumArray[sampleDataIndex]/intervalInSeconds;
allAveragesForCurrentInterval.push(avg);
}
meanMaxByTimeFrame.push({'Interval': intervalInSeconds, 'MeanMax': Math.max.apply(Math, allAveragesForCurrentInterval)});
sampleDataMaxIndex--;
}
console.log(meanMaxByTimeFrame)
let time = performance.now();
console.log('Duration: ' + (time - start) + ' ms.');
If you want to run it: https://jsfiddle.net/7f0zrnq2/1/

fast way to check a number is in a range of a group of numbers

I just encounter a scenario like the following. It sounds a little bit like a leetcode question.
Support I can get a list of number in a pattern, to simplify my questions.
For example, [0, 5, 10, 15, 20, 25] or [0,7,14,21], it's already sorted.
then given a range (I can guarantee range will never overlap between two consecutive numbers)
for example, range=2;
If num=11, then I supports to get index of 10 because 11 is in a range of 10-2 to 10+2.
If num=12.5, then I will just return -1 or anything else to indicate we does not find.
I can simply go through the list and check if the number is in the range of each number but I feel like there is a O(1) solution since the list itself has some pattern exist. any help is greatly appreciated.
Diff is also provided, the above example diff=5.
I does not encounter any performance issue now with O(N) list checking, just want to make thing better.
You could use Array.some to check if the number (and range) overlaps with your list, for example:
This will be O(n), and I suspect you will need a very large list indeed to justify creating an O(1) type solution.
We can go the other way, creating an array of candidate numbers (numbers within the range, e.g. for 10 +- 2 this would be [8,9,10,11,12]. NB: This approach will not work for floating point values.
We check each number for membership of a set created from the list. This will still technically be O(n), but N will most likely be small (e.g. 5).
let list = [0, 5, 10, 15, 20, 25];
// This solution will need at most N iterations, where N is the length of list
function checkInRange(value, range, list) {
return list.some((el) => {
return (el >= (value - range)) && (el <= (value + range));
})
}
// This solution will need at most N iterations, where N is the length of a, e.g. 2 * range + 1
function checkInRangeSet(value, range, list) {
// Create an array of matching numbers, e.g. 8,9,10,11,12
let a = Array.from({ length: 2*range + 1 }, (v,k) => value - range + k);
let set = new Set(list);
return a.some((el) => {
return set.has(el);
})
}
console.log("Solution with simple loop");
console.log(checkInRange(11, 1, list));
console.log(checkInRange(10, 0, list));
console.log(checkInRange(30, 5, list));
console.log(checkInRange(9, 0, list));
console.log(checkInRange(100, 20, list));
console.log("Solution with Set");
console.log(checkInRangeSet(11, 1, list));
console.log(checkInRangeSet(10, 0, list));
console.log(checkInRangeSet(30, 5, list));
console.log(checkInRangeSet(9, 0, list));
console.log(checkInRangeSet(100, 20, list));
Here's my shot at an O(1) solution.
const list = [0, 7, 14, 21, 28];
const interval = list[1];
const range = 2;
function getIndex(num, range) {
const halfItvl = interval / 2;
const inRange = Math.abs((num % interval) - halfItvl) >= halfItvl - range;
return inRange ? Math.trunc((num + halfItvl) / interval) : -1;
}
// Test for all numbers within the list
for (var i = 0; i < list[list.length - 1]; i++) {
const res = getIndex(i, range);
if (res === -1) {
console.log(`${i} is out of range ${range}`);
} else {
console.log(`${i} is within range ${range} of index ${res}`);
}
if (i % interval === interval - 1) {
console.log("---------------------");
}
}
Actually, it seems a good bit simpler if I establish the index first. Then all we need to do is subtract the current number from the value at the found index, take its absolute value, and see if it's less than or equal to the given range number.
const list = [0, 7, 14, 21, 28];
const interval = list[1];
const range = 2;
function getIndex(num, range) {
const idx = Math.trunc((num + (interval / 2)) / interval);
return Math.abs(list[idx] - num) <= range ? idx : -1;
}
// Test for all numbers within the list
for (var i = 0; i < list[list.length - 1]; i++) {
const res = getIndex(i, range);
if (res === -1) {
console.log(`${i} is out of range ${range}`);
} else {
console.log(`${i} is within range ${range} of index ${res}`);
}
if (i % interval === interval - 1) {
console.log("---------------------");
}
}

Given an array, count the pairs whose sums are multiples of 60

Given an array, how do you find the number of couples (two values) that add up to 60 or a value divisible by 60. Note: Must be faster than O(N^2).
Input: [10, 50, 30, 90]
Output: 2
Reasoning: 10+50 = 60, 30 + 90 = 120 ( 120 is divisible by 60)
Input: [60,60,60]
Output: 3
Reasoning: 60 + 60 = 120, 60 + 60 = 120, 60 + 60 = 120
The code I have below would run in O(N) time, but I do not know how to take care of the pairs that are equal to each other (ie if you have 2 30 values in the array that would add 1 to your counter, but if you have 3 30 values in the array that would add 3 to your counter). I figured I should create a combination function (ie 2C2 or 3C2), but that is a linear function and wouldn't that just make the function back to O(N^2)?
values(myList) {
var obj = {};
var count = 0;
// loop through array and mod each value and insert it into a dictionary
myList.forEach((elem, index) => {
if (!obj.hasOwnProperty(elem % 60)) {
obj[elem % 60] = 1;
} else {
obj[elem % 60]++;
}
});
for (var keys in obj) {
if (obj.hasOwnProperty(60 - keys)) {
if (60 - keys == keys) {
// take care of pairs
// obj[keys] = x --> xC2
} else {
count += Math.min(obj[keys], obj[60 - keys]);
delete obj[keys]
delete obj[60 - keys];
}
}
}
return count;
}
There is no combination needed. It's simple math.
It's n * (n-1) / 2.
Let's say you have 4 items a,b,c,d.
Pairs would be:
(a,b)
(a,c)
(a,d)
(b,c)
(b,d)
(c,d)
For 4 items, we have 4 * 3 / 2 = 6.
#UPDATE:
Change
count += Math.min(obj[keys], obj[60 - keys]);
to
count += obj[keys] * obj[60 - keys];
Consider 2 keys- 12 and 48.
Key 12 has elements - 12,72,132
Key 48 has elements - 48,108
Technically, you are storing counts for them, which will be 3 and 2.
If you observe, total no. of pairs we can make is 3 * 2 = 6 and not Math.min(3,2);
You can compute nC2 in O(1) time, because nC2 = n!/(n−2)!·2! = n·(n−1)·(n−2)!/(n−2)!·2! = n·(n−1)/2! = n·(n−1)/2.
That said, you might want to consider a different approach: instead of having a separate loop to compute count based on obj, you can add to count as you are building obj. That might be more intuitive, since it eliminates the need for special cases. (Up to you.)
Incidentally, your if (60 - keys == keys) test is not correct; that will detect the case where keys == 30, but not the case where keys == 0. (There may also be some other bugs you'll need to sort through.)
If we count the pairs each element can make with the numbers seen so far, we can use simple addition rather than manage combinatorics or delicate edge cases.
function f(A, m){
const rs = new Array(m+1).fill(0);
for (let x of A){
if (rs[(m - x % m) % m])
rs[m] += rs[(m - x % m) % m];
rs[x % m]++;
}
return rs[m];
}
console.log(f([10, 50, 30, 30], 60));
console.log(f([30, 10, 50, 30, 30], 60));
console.log(f([1, 5, 3, 3, 6, 24], 6));
(By the way, I'm not sure why you are making a differentiation between two numbers that add up to 60 and pairs that sum to a value divisible by 60 since the former is contained in the latter.)
update: this solution is n^2, so this does not answer the original question.
let values = [60,10,20,50,40,30, 120, 60, 10];
let count = 0;
for (let i = 0; i < values.length; i++){
for (let j = i+1; j < values.length; j++){
let v = values[i] + values[j];
if (v == 60 || !(v % 60)){
count++;
}
}
}
update 2:
To make it n + n*log(n), one could create a sorted tree with the mod values and then iterate through each of the mod value and look for 60-mod value values to find the number of pairs making up the difference. nodes can be optimised storing the number of repetitions as well. would that solve your problem?

Categories

Resources