How calculate changing slider values with a maximum value for all? - javascript

I need to create a slider for a game that you can set skills to each player,
The rules are :
Each skill starts at 0.
The skills cannot total more than 100 points at any time.
It should always be possible to assign any 0-100 value to a given skill. Given rule (2), if this gets us over 100 total points, the excess automatically, immediately, removed from the other skills, according to their current values.
It's not required to use all 100 points (or any).
A skill's value is always an integer.
For example :
We start with:
Stamina: 0 | Speed: 0 | Armor: 0 | Strength: 0 | Remaining: 100
The player adds 50 Speed.
Stamina: 0 | Speed: 50 | Armor: 0 | Strength: 0 | Remaining: 50
The player adds 25 Armor.
Stamina: 0 | Speed: 50 | Armor: 25 | Strength: 0 | Remaining: 25 - 115
The player now adds 40 Stamina. The excess is automatically reduced from the other skills, weighted by their current values.
Stamina: 40 | Speed: 40 | Armor: 20 | Strength: 0 | Remaining: 0
The player then reduces Speed to 10.
Stamina: 40 | Speed: 30 | Armor: 20 | Strength: 0 | Remaining: 10
Finally, the player sets Strength to 100.
Stamina: 0 | Speed: 0 | Armor: 0 | Strength: 100 | Remaining: 0
To do so i've created a function the receives 3 arguments :
An array of values of the slider
let arrToCalc = [14,24,55,0]
The index number of the skill (0 for Stamina, 1 for Speed ...etc)
let newValueIndex = 2
New value for base the calculation on
let newVal = 64.
Im not sure my calculations are accurate so i'm getting partial good results.
when set to
let arrToCalc = [0,50,25,0]
let newValueIndex = 0
let newVal = 40
the results are fine - [40,40,20,0]
but when i'm testing it with with other values - it's not always correct.
function calcSkills(currentValues, newValue, newValueIndex) {
let outArr = [];
for (let i = 0; i < currentValues.length; i++) {
if (i == newValueIndex) {
currentValues[i] = newValue;
}
}
let calcValues = currentValues.reduce((a, b) => {
return a + b;
})
if (calcValues < 100) {
outArr = currentValues
console.log('less', outArr)
} else {
let accumulator = 0;
let isValidVal = false;
for (let i = 0; i < currentValues.length; i++) {
let val = currentValues[i];
if (val && i !== newValueIndex) {
let temp = 0;
if (accumulator == 0) {
isValidVal = (100 - (newValue + val) >= 0 ? true : false);
if (isValidVal) {
temp = val - (100 - (newValue + val));
} else {
temp = 0;
}
accumulator = newValue
} else {
accumulator = accumulator + accumulator;
isValidVal = (100 - accumulator) > 0 ? true : false;
if (isValidVal) {
temp = val - (val - (100 - accumulator));
} else {
temp = 0;
}
}
outArr.push(temp)
} else {
outArr.push(val)
}
}
console.log('greather', outArr)
}
}
arrToCalc = [44, 55, 25, 0]
newValueIndex = 2
newVal = 40
calcSkills(arrToCalc, newVal, newValueIndex)

This approach uses 2 reduce() cycles, one to set the new values, and the next to shave or add the tiny bit left over. I have put in a half-dozen tests below, they all add up.
function calcSkills(curV, nV, nvI) {
console.log("---------------\nrunning calcSkills")
console.log("curV", curV.join(","));
console.log('newValue', nV, 'at index', nvI)
curV[nvI] = nV
let cValues = curV.reduce((a, b) => a + b)
if (cValues < 100) { outArr = curV }
else {
console.log(typeof curV)
let newOrder = [...curV]
newOrder.sort((a, b) => a - b)
let orderMap = newOrder.reduce((b, a) => {
let tmp = curV.indexOf(a);
let ct = 0;
while (b.indexOf(tmp, ct) !== -1) {
tmp = curV.indexOf(a, tmp + 1)
ct++
}
b.push(tmp);
return b
}, [])
let uvalueIndex = newOrder.indexOf(curV[nvI])
curV = newOrder, nvI = uvalueIndex, outArr = [], diff = cValues - 100, ttl = 0, nonz = 0;
let nvals = curV.reduce((b, a, i) => {
if (nvI !== i) a = a - Math.floor(a / 100 * diff); // if not the newly added number, find out our relative percentage and subtract it from the original number
b.push(a);
ttl += a;
if (a != 0 && nvI !== i) nonz++;
return b
}, []);
let overage = (ttl % 100),
ldiff = Math.ceil(overage / nonz) * (ttl > 100 ? -1 : 1); // ldiff determines how to spread the overage/underage so we get to 100
let numspots = Math.ceil(Math.abs(ldiff) / nonz)
nvals = nvals.reduce((b, a, i) => {
if (a !== 0 && nvI !== i && numspots > 0) {
let fval = a + ldiff
if (fval < 0) ldiff += Math.abs(fval)
a += ldiff;
overage += ldiff
nonz--;
if (nonz < 1) a -= overage
}
b.push(a);
return b;
}, [])
// reassemble
//console.log(nvals.join(","), orderMap.join(","))
orderMap.forEach((o, i) => outArr[o] = nvals[i])
}
console.log('Result:', outArr.join(","));
return outArr
}
/*-------- Testing ----------*/
arrToCalc = [0, 0, 67, 33]
nvI = 1
newVal = 75
calcSkills(arrToCalc, newVal, nvI)
arrToCalc = [3, 13, 44, 1]
nvI = 1
newVal = 74
calcSkills(arrToCalc, newVal, nvI)
arrToCalc = [1, 20, 61, 18]
nvI = 2
newVal = 76
calcSkills(arrToCalc, newVal, nvI)
arrToCalc = [0, 50, 25, 0]
nvI = 0
newVal = 40
calcSkills(arrToCalc, newVal, nvI)
/*
arrToCalc = [0, 60, 25, 0]
nvI = 3
newVal = 40
calcSkills(arrToCalc, newVal, nvI)
arrToCalc = [50, 40, 10, 0]
nvI = 3
newVal = 40
calcSkills(arrToCalc, newVal, nvI)
arrToCalc = [80, 10, 10, 0]
nvI = 3
newVal = 60
calcSkills(arrToCalc, newVal, nvI)
*/

After calculating the total score, reduce that from 100, and store it in the variable (here extra), then run a while loop utill that value becomes 0.
In the below snippet, I am running a loop and in each iteration reducing the value by 10. You can change the reduction logic as per the requirement.
function calcSkills(currentValues, newValue, newValueIndex){
for(let i =0; i < currentValues.length; i++){
if(i == newValueIndex){
currentValues[i] = newValue;
}
}
let calcValues = currentValues.reduce((a,b)=>{
return a +b;
})
if(calcValues < 100){
console.log('less', currentValues)
}
else {
let isValidVal = false;
let extra = calcValues - 100;
while(!isValidVal) {
for(let i=0; i<currentValues.length; i++) {
if (i != newValueIndex && currentValues[i] > 0) {
if (extra >= 10) {
currentValues[i] -= 10;
extra -= 10;
} else {
currentValues[i] -= extra;
extra = 0;
}
}
}
if (extra == 0) {
isValidVal = true;
}
}
console.log('greather', currentValues)
}
}
arrToCalc = [44, 55, 25, 0]
newValueIndex = 2
newVal = 40
calcSkills(arrToCalc, newVal, newValueIndex)

This is my attempt at the problem, I'm not sure a possible remainder is always going to land in the most desirable place, maybe that's something that could be tweaked.
const distribute_remainder_for_indexes = (arr, indexes, remainder) => {
const sorted_indexes = [...indexes].sort((a, b) => arr[b] - arr[a]);
return arr.map((v, i) => {
const ii = sorted_indexes.indexOf(i);
return v - ((ii > -1 && ii < remainder) ? 1 : 0);
});
};
const distribute_reduction_for_indexes = (arr, indexes, reduction) => {
const total = indexes.reduce((acc, v) => acc + arr[v], 0);
const reduced = arr.map((v, i) => v - (indexes.includes(i) ? Math.floor(v * reduction / total) : 0));
return distribute_remainder_for_indexes(
reduced, indexes,
indexes.reduce((acc, v) => acc + reduced[v], 0) - (total - reduction)
);
};
function calcSkills(current, new_value, new_index) {
const max_value = 100;
let copy = [...current];
copy[new_index] = Math.min(new_value, max_value);
const excess = copy.reduce((a, b) => a + b) - max_value;
return excess > 0 ?
distribute_reduction_for_indexes(
copy,
copy.reduce((a, v, i) => i !== new_index && v > 0 ? a.concat(i) : a, []),
excess
) :
copy;
}
console.log("[44, 55, 25, 0], 40, 2 ::", ...calcSkills([44, 55, 25, 0], 40, 2));
console.log("[0, 50, 25, 0], 40, 0 ::", ...calcSkills([0, 50, 25, 0], 40, 0));
console.log("[44, 13, 3, 1], 74, 1 ::", ...calcSkills([44, 13, 3, 1], 74, 1));
console.log("[80, 10, 10, 0], 60, 3 ::", ...calcSkills([80, 10, 10, 0], 60, 3));
console.log("[0, 9, 90, 1], 60, 0 ::", ...calcSkills([0, 9, 90, 1], 60, 0));
console.log("[0, 10, 50, 0], 20, 0 ::", ...calcSkills([0, 10, 50, 0], 20, 0));
console.log("[0, 10, 10, 8], 73, 0 ::", ...calcSkills([0, 10, 10, 8], 73, 0));
console.log("[0, 8, 10, 10], 73, 0 ::", ...calcSkills([0, 8, 10, 10], 73, 0));

Related

try to create if to stop get numbers higher then 20 javascript

i tray to build function to show the high and lowest number but between 0 and 20
"use strict";
let scors = [50, 70, 60, 20, 15, 14, 12, 10, 9, 8, -5, 4, 16, 2, 17.5, 12.75];
function minMax(score) {
let max = score[0];
let min = score[0];
for (let i = 0; i < score.length; i++) {
if (score[i] < min && score[i] >= 0) {
min = score[i];
}
//this part dose not work
if (score[i] > max && score[i] <= 20) {
max = score[i];
}
}
console.log(max);
console.log(min);
}
minMax(scors);
These are the conditions you applied, the current score must be greater than max and less than 20.
if (score[i] > max && score[i] <= 20) {
max = score[i];
}
This is an example of 4th first iteration.
Iteration 1: input: 50 > max: 50
Iteration 2: input: 70 > max: 50
Iteration 3: input: 60 > max = 50
Iteration 4: input: 20 > max = 50
In the 4th iteration, the max is not assigned as 20 because it doesn't greater than the current max which is 50.
Here is the simple solution:
Add score.sort(); for sorting the array before start looping.
Define the min with the last index of the array.
'use strict';
let scors = [50, 70, 60, 20, 15, 14, 12, 10, 9, 8, -5, 4, 16, 2, 17.5, 12.75];
function minMax(score) {
score.sort();
let max = score[0];
let min = score[score.length - 1];
for (let i = 0; i < score.length; i++) {
if (score[i] < min && score[i] >= 0) {
min = score[i];
}
// This part now works!
if (score[i] > max && score[i] <= 20) {
max = score[i];
}
}
console.log(max);
console.log(min);
}
minMax(scors);
For the range of 0 - 20 you can bound the min and the max which would eliminate the need to sort the array.
Time complexity O(N).
'use strict';
let scors = [50, 70, 60, 20, 15, 14, 12, 10, 9, 8, -5, 4, 16, 2, 17.5, 12.75];
function minMax(score) {
let max = -1;
let min = 21;
for (let i = 0; i < score.length; i++) {
if (score[i] < min && score[i] >= 0) {
min = score[i];
}
// This part now works!
if (score[i] > max && score[i] <= 20) {
max = score[i];
}
}
console.log(max);
console.log(min);
}
minMax(scors);

Find upper and lower boundaries in array

I am trying to get the upper and lower boundaries of a numeric value in an array.
const boundaries = [15, 30, 45, 60, 75, 90];
const age = 22;
For the above example, the outcome should be:
[15, 30]
If for example the value is a boundary, it would become the lower value in the outcome array. If it is the max boundary or above, it should become the max value.
Example outcomes:
15 => [15, 30]
22 => [15, 30]
30 => [30, 45]
90 => [90]
I tried mapping through the array and if the age is higher => return boundary. Then filter out the boundaries and calculate the indexes, but this doesn't feel like the correct way to accomplish this.
const boundaries = [15, 30, 45, 60, 75, 90];
const age = 22;
// get all lower values
const allLower = boundaries.map((b) => age > b ? b : null).filter(x => x);
const lower = allLower[allLower.length - 1]; // get lowest
const upper = boundaries[boundaries.indexOf(lower) + 1]; // get next
const result = [lower, upper]; // form result
console.log(result);
Is there a shorter / better / more reliable way to do this?
Why do you use the indices for this? What if the boundaries array is not sorted? Wouldn't it be easier to filter the lists to allLower and allUpper (containing the values below and above the threshold), and then use min and max on the resulting arrays?
Sample code:
const boundaries = [15, 30, 45, 60, 75, 90];
const age = 22;
const allLower = boundaries.filter(x => x < age);
const allUpper = boundaries.filter(x => x > age);
const lowerBound = Math.max(...allLower);
const upperBound = Math.min(...allUpper);
Looks like a good use case for reduce:
const boundaries = [15, 30, 45, 60, 75, 90];
for (let search of [1, 22, 30, 90, 100]) {
let [low, upr] = boundaries.reduce(([low, upr], x) =>
[
x <= search ? Math.max(low, x) : low,
x > search ? Math.min(upr, x) : upr,
],
[-Infinity, +Infinity]
)
console.log(low, '<=', search, '<', upr)
}
This doesn't require boundaries to be sorted. If they always are, you might consider binary search to locate the lower bound.
Looks like a plain for-loop might help you out ;)
function getBounds(age) {
for (let i = 0; i < boundaries.length; i++) {
if (boundaries[i] <= age && (boundaries[i + 1] ?? Infinity) > age) {
return boundaries.slice(i, i + 2);
}
}
}
You could check the previous value and next value and filter the array.
const
getLowerUpper = (array, pivot) => array
.filter((v, i, { [i - 1]: prev, [i + 1]: next }) =>
v <= pivot && next > pivot ||
prev <= pivot && v >= pivot ||
prev === undefined && next > pivot ||
prev < pivot && next === undefined
),
boundaries = [15, 30, 45, 60, 75, 90];
console.log(...getLowerUpper(boundaries, 22)); // between
console.log(...getLowerUpper(boundaries, 30)); // direct and next
console.log(...getLowerUpper(boundaries, 10)); // lowest
console.log(...getLowerUpper(boundaries, 15)); // direct and next
console.log(...getLowerUpper(boundaries, 90)); // highest
console.log(...getLowerUpper(boundaries, 100)); // highest
You can reduce the array, something like this:
const boundaries = [15, 30, 45, 60, 75, 90];
const getResult = (array, target) => {
if (target < array[0] || target > array[array.length - 1]) {
return [];
}
return array.reduce((a, c) => {
if (c <= target) {
a[0] = c;
} else if (c > target && (!a[1] || c < a[a.length - 1])) {
a[a.length] = c;
}
return a;
}, []);
}
console.log(getResult(boundaries, 22));
console.log(getResult(boundaries, 15));
console.log(getResult(boundaries, 30));
console.log(getResult(boundaries, 90));
console.log(getResult(boundaries, 14));
console.log(getResult(boundaries, 91));

How to receive only even numbers from summing values of two arrays in javascript?

I try to receive only even numbers, summing values from two arrays. If the result cannot be even, it should return one even value without summing being executed.
These are two arrays:
var a = [-2, 10, 30, 50, 11, 22, 100];
var b = [10, 8, 22, 5, 11, -5];
So, the result should be :
[8, 18, 52, 50, 22, 22, 100],
which stems from the following:
-2 + 10 = 8 (even), 10 + 8 = 18 (even),
30 + 22 (even), 50 + 5 = 55 (not even),
so 50 should be, because it is even, 11 + 11 = 22 (even), 22 + (-5) = 17 (not even), so 22 should be, because it is even, 100 is even.
I have the code, but it returns boolean "true" instead of 50 and second 22. How that can be fixed?
function sumArray(a, b) {
var c = [];
for (var i = 0; i < Math.max(a.length, b.length); i++) {
c.push((a[i] || 0) + (b[i] || 0));
}
return c;
}
var a = [-2, 10, 30, 50, 11, 22, 100];
var b = [10, 8, 22, 5, 11, -5];
var numbers = sumArray(a, b);
function OnlyEvens(numbers) {
;
var evens = [];
for(var i = 0; i < numbers.length; i++){
if(numbers[i]%2 == 0) evens.push(numbers[i]);
else (evens.push (a[i] % 2 == 0 || b[i] % 2 == 0))
}
return evens
}
var check = OnlyEvens(numbers);
console.log(check)
When you tried to push the array a number in case it's not even, you actually pushed the result of the condition which will give you a boolean result true/false.
a[i] % 2 == 0|| b[i] % 2 == 0
What you can possibly do is add a ternary condition. if a[i] is even, then push that value to the array. else, push b[i] (since it must be even because uneven + uneven gives you an even number, hence it will enter the
a[i] + b[i] % 2 === 0
condition on the first if.
function sumArray(a, b) {
var c = [];
for (var i = 0; i < Math.max(a.length, b.length); i++) {
c.push((a[i] || 0) + (b[i] || 0));
}
return c;
}
var a = [-2, 10, 30, 50, 11, 22, 100];
var b = [10, 8, 22, 5, 11, -5];
var numbers = sumArray(a, b);
function OnlyEvens(numbers) {
;
var evens = [];
for(var i = 0; i < numbers.length; i++){
if(numbers[i]%2 == 0) evens.push(numbers[i]);
else (evens.push (a[i] % 2 == 0 ? a[i] : b[i] ))
}
return evens
}
var check = OnlyEvens(numbers);
console.log(check)
You could check the remainder and get either both values or just a single one.
function sumEven(a, b) {
return a.map((v, i) =>
v % 2 === b[i] % 2
? v + b[i]
: v % 2
? b[i]
: v
);
}
const
a = [-2, 10, 30, 50, 11, 22, 100],
b = [10, 8, 22, 5, 11, -5];
console.log(...sumEven(a, b));
Another approach with finding the value.
function sumEven(a, b) {
return a.map((v, i) => [v + b[i], v, b[i]].find(v => v % 2 === 0));
}
const
a = [-2, 10, 30, 50, 11, 22, 100],
b = [10, 8, 22, 5, 11, -5];
console.log(...sumEven(a, b));
You could recurse over the values of both arrays ( a and b ) and add the even total or even value to the new array. After that add the leftover values to the result ( assumed they can be both odd or even in the code below ).
var a = [-2, 10, 30, 50, 11, 22, 100];
var b = [10, 8, 22, 5, 11, -5];
let c = [];
while( a.length > 0 && b.length> 0 ) {
let val_1 = a.shift();
let val_2 = b.shift();
let total = val_1 + val_2;
if( is_even(total) )
c.push( total );
else if ( is_even(val_2) )
c.push( val_2 );
else if ( is_even(val_1) ) // unnecessary check
c.push( val_1 );
}
// add leftover values (always)
c = c.concat(a).concat(b);
console.log(c);
function is_even( integer ) {
return integer % 2 === 0;
}

How to get single even or odd number from a array in simplest way?

To get single even or odd number from a array. Example:
[20, 10, 11, 200, 30] => will return 11.
[31, 23, 45, 20, 43] => will return 20.
I have tried the below function to achieve this requirement:
function getEvenOrOddNum(arr) {
var checkVal, num, i, len = arr.length;
if (len > 2) {
for (i = 0; i < 3; i++) {
var mod = arr[i] % 2;
if (checkVal == mod) { break; }
checkVal = mod;
}
checkVal = checkVal == 0 ? 1 : 0;
num = arr.filter((val) => val % 2 == checkVal);
num = num.length < 2 ? num[0] : null;
}
return num || null;
}
console.log(getEvenOrOddNum([20, 10, 11, 200, 30])) //=> return 11
console.log(getEvenOrOddNum([31, 23, 45, 20, 43])) //=> return 20
console.log(getEvenOrOddNum([20, 10])) //=> return null
console.log(getEvenOrOddNum([20, 10, 11, 23, 200, 30])) //=> return null
console.log(getEvenOrOddNum([31, 23, 45, 20, 43, 50])) //=> return null
You could coount the types and store the last value of each type and check if two values have the same type, then take a flag for the wanted type.
Return then the type with the flag and check the count before.
l means the left element and r the right one which is the actual item as well. Bothe elements are neede for comparing both types of even/odd.
For example:
vv actual item
[20, 10, 11, 200, 30] array
l r variables
function getSingle(array) {
var count = [0, 0],
values = [],
flag;
array.forEach((r, i, { length, [(length + i - 1) % length]: l }) => {
if (l % 2 === r % 2) flag = 1 - r % 2;
values[r % 2] = r;
count[r % 2]++;
});
return count[flag] === 1
? values[flag]
: null;
}
console.log(getSingle([20, 10, 11, 200, 30])); // 11
console.log(getSingle([31, 23, 45, 20, 43])); // 20
console.log(getSingle([20, 10])); // null
console.log(getSingle([20, 10, 11, 23, 200, 30])); // null
console.log(getSingle([31, 23, 45, 20, 43, 50])); // null
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.prototype.find().
This will call the provided function for each array element, and will return the first element which 'match the condition' (the provided function returns true for):
const evenArray=[2,4,6,8,9]
const oddArray=[1,2,3,5,7,9]
console.log(evenArray.find(element=> element % 2 === 1)) //9
console.log(oddArray.find(element=> element % 2 === 0)) //2

Put the 0 at the same position on two arrays in javascript

Sorry for my english, really really tired...
Imagine two arrays:
var a = [-10, 5, 0, 5, 10, 15];
var b = [-20, 0, 20, 40, 60, 80];
Every value of each array increments by the same number (a by 5 and b by 20).
I would like to find a way to put the zero on the same position on both arrays.
Keep in mind that:
each serie has the same number of elements
you can change the min and max value of each array (the original min and max of a serie have to be a part of the serie, check the example below)
each value of the array increments by the same number, you can change this value
The expected result could be something like
var a = [-10, 5, **0**, 5, 10, 15];
var b = [-60, -30, **0**, 30, 60, 90];
b increments now by 30 and the original min (-20) and max (8) values are included in the interval.
Any idea on how to do that using javascript?
Why I'd like to do that? To solve something like that:
http://peltiertech.com/Excel/Charts/AlignXon2Ys.html
Thanks in advance
Rob
The following is a result of code iteration based on comments. Previous code has been removed for clarity, but remains available in edit history.
This one fixes the zero in the middle of a series, then adjusts values according to the initial requirements. Also rounding to the nearest 5 (previous code was inadequate in that regard, sorry). HTH.
function develop(data) {
if (data.length < 3) {
return data;
}
var lower = data[0];
var upper = data[data.length - 1];
var index = (data.length - 1) / 2;
var numLeft = Math.floor(index);
var numRight = Math.ceil(index);
var leftStep = findStep(lower, numLeft, false);
var rightStep = findStep(upper, numRight, true);
var step = roundStep(Math.max(leftStep, rightStep), 5);
var result = [];
for (var ii = 0; ii < data.length; ii++) {
result[ii] = step * (ii - numLeft);
}
return result;
// ---
function findStep(boundary, numEntries, positive) {
if (positive && boundary <= 0 || !positive && boundary >= 0) {
return 1;
}
return Math.abs(Math.ceil(boundary / numEntries));
}
function roundStep(step, roundTo) {
if (step < roundTo) {
return step;
}
return Math.ceil(step / roundTo) * roundTo;
}
}
function test() {
var testData = [
[-10, -5, 0, 5, 10, 15],
[-20, 0, 20, 40, 60, 80],
[0, 72, 144, 216, 288, 360],
[-30, -25, -20, -15, -10, 0]
];
var results = [];
for (var ii = 0; ii < testData.length; ii++) {
var data = testData[ii];
results.push(JSON.stringify(data) + " => " + develop(data));
}
document.getElementById("results").innerHTML = results.join("<br>");
}
<input type="button" value="test()" onclick="test()" />
<div id="results"></div>
This seems to work, but I'm probably doing couple thins not necessary
var setIndex = function (arr1, arr2) {
var arr1Min = arr1[0];
var arr2Min = arr2[0];
var arr1Max = arr1[arr1.length-1];
var arr2Max = arr2[arr2.length-1];
var length = arr1.length;
var newRatio;
var newMin;
var newMax;
var ratioArr1 = arr1Max/arr1Min;
var ratioArr2 = arr2Max/arr2Min;
if(ratioArr1 < ratioArr2){
newMin = calcNewMin(arr1Min, arr1Max, ratioArr2);
newMax = ratioArr2 * newMin;
newRatio = (newMax - newMin)/(length-1);
arr1 = [];
for(var i = 0; i < length; i++){
arr1.push(newMin + (i * newRatio));
}
return [arr1, arr2];
} else {
newMin = calcNewMin(arr2Min, arr2Max, ratioArr1);
newMax = ratioArr1 * newMin;
newRatio = (newMax - newMin)/(length-1);
arr2 = [];
for(var i = 0; i < length; i++){
arr2.push(newMin + (i * newRatio));
}
return [arr1, arr2];
}
};
var calcNewMin = function(min, max, ratio){
var count = 1;
var newMin = min;
var newMax = max;
while(newMax <= max){
count++;
newMin = min - count;
newMax = newMin * ratio;
}
return newMin;
};
Compare the array ranges first, if one array includes the range of the other one then the answer is a series with an increment higher than the array that increments where the start of the range is:
0 - increment * (position of 0)
In your example:
var a = [-10, 5, 0, 5, 10, 15];
var b = [-20, 0, 20, 40, 60, 80];
b includes the range of a, so any series that have an increment higher than b and obeys the rules at the beginning are valid solutions to the problem:
[-20, 0, 20, 40, 60, 80]
[-21, 0, 21, 42, 63, 84]
[-22, 0, 22, 44, 66, 88]
...
[-60, 0, 60, 120, 180, 240]
All of these series include the range of a.
It gets a little bit trickier when the ranges overlap:
[-10, 0, 10, 20, 30]
[ 0, 20, 40, 60, 80]
The idea behind is the same. We'll pick the series with the smallest value:
[-10, 0, 10, 20, 30]
From this, we'll need to find a higher increment so that it satisfies:
start + (inc * length) > max of other series.
Where start:
0 - (inc * pos of 0 in picked series)
Moving stuff around you get:
inc > (max value / (length - pos of 0 in picked series))
So in this example:
inc > 80 / (5 - 2)
inc > 80 / 3
inc > 26.666
Lets try it with an increment of 27 and a start of -27:
[-27, 0, 27, 54, 81]
Now, that you we know how to solve the problem, lets try it with code:
function getMinMax(a, b){
var last = a.length - 1,
min = a[0] < b[0] ? a : b,
max = a[last] > b[last] ? a : b;
return { min : min, max : max };
}
function closestInc(range){
if(range.min === range.max){
return range.min[1] - range.min[0];
} else {
var last = range.min.length - 1,
maxValue = range.max[last],
posOfCero = range.min.indexOf(0);
return (maxValue/(range.min.length - posOfCero));
}
}
So, all the possible answers would be any series with an increment value bigger than closestInc(a, b) and a start of -closestInc(a,b) * posOfCero.
Here's a function that prints out all possible values slowly:
function createSeries(inc, posOfCero, count) {
var series = [],
start = -(inc * posOfCero);
for (var i = 0; i < count; i++) {
series.push(start + (inc * i));
}
return series;
}
var a = [-10, 5, 0, 5, 10, 15],
b = [-20, 0, 20, 40, 60, 80],
ranges = getMinMax(a, b),
inc = closestInc(ranges),
posOfCero = ranges.min.indexOf(0);
setTimeout(function printSeries(i) {
console.log(createSeries(inc + 1, posOfCero, range.min.length));
setTimeout(printSeries, 1000, i + 1);
}, 1000, 1);
A snippet below:
function getMinMax(a, b) {
var last = a.length - 1,
min = a[0] < b[0] ? a : b,
max = a[last] > b[last] ? a : b;
return {
min: min,
max: max
};
}
function closestInc(range) {
if (range.min === range.max) {
return range.min[1] - range.min[0];
} else {
var last = range.min.length - 1,
maxValue = range.max[last],
posOfCero = range.min.indexOf(0) + 1;
return (maxValue / (range.min.length - posOfCero));
}
}
function createSeries(inc, posOfCero, count) {
var series = [],
start = -(inc * posOfCero);
for (var i = 0; i < count; i++) {
series.push(start + (inc * i));
}
return series;
}
//var a = [-10, 5, 0, 5, 10, 15],
// b = [-20, 0, 20, 40, 60, 80],
var a = [-10, 0, 10, 20, 30],
b = [ 0, 20, 40, 60, 80],
ranges = getMinMax(a, b),
inc = closestInc(ranges),
posOfCero = ranges.min.indexOf(0);
setTimeout(function printSeries(i) {
console.log(createSeries(Math.round(inc + i), posOfCero, ranges.min.length));
setTimeout(printSeries, 1000, i + 1);
}, 1000, 1);
A last note, this aren't all possible series to match your rules (there might still be some valid increments between the series).
You can use Array.push and Array.unshift like this jsFiddle

Categories