Put the 0 at the same position on two arrays in javascript - 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

Related

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

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));

Calculate Conway's Constant

I found a code golf challenge that requires you to calculate Conway's Constant to the first 1000 digits. The problem is I couldn't find any place that tells how to calculate this, just websites showing polynomials with a variable x that I do not know what is.
I calculated the first 30 numbers in the Look-and-say sequence with this code:
const nums = ["1"],
trailingSequences = seq => {
const num = seq[0];
let counter = 1;
let idx = 0;
for (let i = 1; i < seq; i++) {
if (num == seq[i]) {
counter++
idx = i;
} else {
break
};
}
return [`${counter}${num}`, idx + 1];
},
getNext = previous => {
let next = "";
while (true) {
if (previous == "") {
break
};
const part = trailingSequences(previous);
next += part[0];
previous = previous.slice(part[1]);
}
return next;
}
for (let i = 0; i < 30; i++)
nums.push(getNext(nums[nums.length - 1]))
console.log(nums.join("\n\n\n"));
But I still do not know how to extract Conway's constant regardless.
So, how to calculate Conway's Constant to a modifiable precision in JavaScript?
Conway's Constant is the unique real positive root of an order-71 polynomial. As you might expect it is irrational1, and cannot be expressed as a finite continued fraction.
One of the easiest, and generally speaking most efficient methods to compute polynomial roots is with Newton's method:
where xn is the current guess and f(xn) is a function that evaluates the target polynomial at xn.
In the case that arbitrary precision reals/rationals are not available, the result can instead be scaled by a large power of 10 to compute the desired precision. The implementation below uses V8's BigInts to compute Conway's Constant to 1000 places.
/**
* Evaluates a polynomial given by coeffs at x,
* or the derivative thereof, scaled by a factor.
*/
function evalpoly(x, coeffs, scale, deriv) {
let ret = 0n;
const d = deriv ? 1 : 0;
for(let i = coeffs.length - 1; i >= d; i--) {
ret = x*ret / scale + BigInt(coeffs[i] * [1, i][d]) * scale;
}
return ret;
}
const poly = [
-6, 3, -6, 12, -4, 7, -7, 1, 0, 5, -2, -4, -12, 2, 7, 12, -7, -10,
-4, 3, 9, -7, 0, -8, 14, -3, 9, 2, -3, -10, -2, -6, 1, 10, -3, 1,
7, -7, 7, -12, -5, 8, 6, 10, -8, -8, -7, -3, 9, 1, 6, 6, -2, -3,
-10, -2, 3, 5, 2, -1, -1, -1, -1, -1, 1, 2, 2, -1, -2, -1, 0, 1]
const scale = 10n**1000n
// initial guess 1.333333...
let x = scale * 4n / 3n
for(let i = 0; i < 14; i++) {
x -= evalpoly(x, poly, scale, 0) * scale / evalpoly(x, poly, scale, 1)
}
x
1 Finch, Steven R., Mathematical Constants, pp. 642, Cambridge University Press, 2003.
The Conway Constant is the ratio between the length of digits of n and n-1 as n approaches inf.
const nums = ["1"],
trailingSequences = seq => {
const num = seq[0];
let counter = 1;
let idx = 0;
for (let i = 1; i < seq; i++) {
if (num == seq[i]) {
counter++
idx = i;
} else {
break
};
}
return [`${counter}${num}`, idx + 1];
},
getNext = previous => {
let next = "";
while (true) {
if (previous == "") {
break
};
const part = trailingSequences(previous);
next += part[0];
previous = previous.slice(part[1]);
}
return next;
}
for (let i = 0; i < 30; i++){
let prev = (nums[nums.length - 1] + '').length;
let current = (getNext(nums[nums.length - 1]) + '').length;
nums.push(getNext(nums[nums.length - 1]))
// ratio of n / n-1, this is the approx of Conway's Constant
console.log(current / prev);
}
//console.log(nums.join("\n\n\n"));

Reset counter when not in range and sum progression

I have an arrays of numbers, and specified range if sequence continues (range rule was met between two numbers) then i add value to result and increase counter by one, else i reset the counter and add nothing to result on this step. Better show in an example:
const numbers = [1, 4, 5, 6, 7, 33, 44, 46]; // they are always going to be from smallest to bigger
const progress = [0, 10, 20, 30, 40, 50, 60]; // 70, 80, etc
let res = 0;
for (let i = 1, j = 0; i < numbers.length; i++) {
const range = numbers[i] - numbers[i - 1];
if (range <= 5) {
j += 1;
res += progress[j];
} else {
j = 0;
}
}
res; // 110
Is there better way to approach this problem?
Well, by looking at your code & the explanation you gave, I think you have incremented 'j' before you added progress for 'j'. that portion should be like following...
if (range <= 5) {
res += progress[j];
j += 1;
}
You have asked for a better approach. But it would help if you specified from which perspective/scenario you are looking for a better approach.
you can do the same with reduce method
const numbers = [1, 4, 5, 6, 7, 33, 44, 46]; // they are always going to be from smallest to bigger
const progress = [0, 10, 20, 30, 40, 50, 60]; // 70, 80, etc
let resp = 0;
const result = numbers.reduce((acc, rec, i, arr) => {
if (rec - arr[i - 1] <= 5) {
resp += 1;
acc = acc + progress[resp];
return acc;
}
resp = 0;
return acc;
}, 0);
result;
You can read more about reduce here
Hope it answers your question.
Happy coding!

Use javascript to sort an array of ints by the distance the element is from a given target

Algorithm: distanceSort(array, target)
Input: An array of ints sorted from least to greatest and an int to measure distance from
Output: The array sorted by distance from target
Example
distanceSort([-10,-6,3,5], 1)
returns [3, 5, -6, -10]
Here's a way to do it. Using Array.sort function
var a = [-10, -6, 3, 5, 99, 76, -100];
function distanceSort(arr, target) {
return arr.sort(function(a, b) {
var distance1 = Math.abs(target - a);
var distance2 = Math.abs(target - b);
return distance1 == distance2 ? 0 : (distance1 > distance2 ? 1 : -1);
});
}
console.log(distanceSort(a, 100)); //[99,76,5,3,-6, -10, -100]
console.log(distance(a, -5)); //[-6, -10, 3, 5, 76, -100, 99]
First, perform a binary search (I always copy from here) to find the target inside the array (if it exists, or the immediatelly greater otherwise).
Then, keep two pointers moving in oposing directions adding always the element with less distance from the target.
The binary search is O(log n) and moving the pointers is O(n). The overall algorithm is O(n).
function lowerBound(arr, target) {
var first = 0,
count = arr.length;
while (count > 0) {
var step = count / 2;
var it = first + step;
if (arr[it] < target) {
first = it + 1;
count -= step + 1;
} else {
count = step;
}
}
return first;
}
function distanceSort(arr, target) {
var answer = [];
var j = lowerBound(arr, target);
var i = j-1;
while (i >= 0 || j<arr.length) {
if (j >= arr.length || target-arr[i]<arr[j]-target)
answer.push(arr[i--]);
else
answer.push(arr[j++]);
}
return answer;
}
console.log(distanceSort([-10,-6,3,5], 1)); //[3, 5, -6, -10]
console.log(distanceSort([-10,-6,3,5], -11)); //[-10, -6, 3, 5]
console.log(distanceSort([-10,-6,3,5], -10)); //[-10, -6, 3, 5]
console.log(distanceSort([-10,-6,3,5], 5)); //[5, 3, -6, -10]
console.log(distanceSort([-10,-6,3,5], 6)); //[5, 3, -6, -10]
var distanceSort = function distanceSort(nArr, x){
return nArr.sort(function(n1, n2){
return Math.abs(n1 - x) - Math.abs(n2 - x);
});
}
console.log(distanceSort([-10,-6, 57, 54, 11, -34, 203, -140, 3, 5], 1));
//--> [3, 5, -6, 11, -10, -34, 54, 57, -140, 203]
It translates nicely into ECMA6 (if you're using Babel) :
var distanceSort = (nArr, x) =>
(nArr.sort((n1, n2) =>
(Math.abs(n1 - x) - Math.abs(n2 - x))));

How to change every 2nd and 3rd element in an array?

Here is my dilemma, I have this code:
var fibs = [1, 2];
for (i = 0; i < (window.innerWidth / 50); i++) {
if (fibs.length < 15) {
var n = fibs[i] + fibs[i + 1];
fibs.push(n);
}
}
Which creates an array of the Fibonacci Sequence. I then copy the contents of fibs to a new array, top. What I'm having trouble with is that I need every 2nd and 3rd elements on top to be the inverse sign of fibs. ie. top[0] = fibs[0]; top[1] = -fibs[1]; top[2] = -fibs[2]; top[3] = fibs[3] I want to be able to do this programmatically because the lengths of the arrays will change based on the width of the screen.
Below is what I'm trying to use.
var top = [];
for (i = 0; i < fibs.length; i++) {
if (i % 2 == 0 || i % 3 == 0) {
top[i] = -(fibs[i]);
} else {
top[i] = fibs[i];
}
}
What I get is [-1, 2,-3, -5, -8, 13, -21, 34, -55, -89, -144, 233, -377, 610, -987], when what I'm looking for is [-1, 2, 3, -5, -8, 13, 21, -34, -55, 89, 144, ... ].
While this might not be the best way to do it, this ought to work:
var topp = [];
for (i = 0; i < fibs.length; i++) {
if (i % 3 == 1 || i % 3 == 2) {
topp[i] = fibs[i] - (2 * fibs[i]);
} else {
topp[i] = fibs[i];
}
}
The code is pretty self explanatory.
EDIT:
Thanks to #alexpods for the tip about the top keyword.
Thanks to #Scott Hunter for pointing out the logical error.
Allow me to throw in a bit more flexible (and readable) solution to your problem:
function fibonacci(length) {
var out = [0, 1];
for (i = 2; i < length; i++) {
out[i] = out[i-1] + out[i-2];
}
return out;
}
function modifyValues(source, factors) {
var out = [];
for (i = 0; i < source.length; i++) {
out[i] = source[i] * factors[i % factors.length];
}
return out;
}
fibs = fibonacci(15);
mod1 = modifyValues(fibs, [1,-1,-1]);
console.log(fibs, mod1);
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
[0, -1, -1, 2, -3, -5, 8, -13, -21, 34, -55, -89, 144, -233, -377]
I believe you want
if ( i%3==1 || i%3==2 ) {
Alternatively, you could use
if ( i%3 ) { // will be treated as true as long as i%3 != 0

Categories