let's say I have an arbitrary number sequence
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
I need to replace all zeroes with interpolation given from non-zeroes neighbours, so the output would be
let output = [
12, 12, 12, 12, 12,
12, 64, 9, 6,
10.75, 15.5, 20.25,
25, 79, 57, 13, 39,
28.3333, 17.6666,
7, 7,
14, 21, 28, 35, 42,
49,
49
];
While firs zeroes [0, 4] doesn't have left neighbour all their values have to be 12, while last zero has only right resident 49, it would be just 49.
For me, it doesn't really a problem to fill parts where both left and right neighbours are presented, however I'm looking for an universal and elegant solution for this task.
const interpolateValues = (array, index0, index1, left, right) => {
let n = index1 - index0 1;
let step = (right - left) / (n 1);
for(let i = 0; i < n; i ){
array[index0 i] = left step * (i 1);
}
}
const findZerosSequences = (array) => {
var counter = 0;
var index = 0;
var result = [];
for (let i = 0; i < array.length; i ) {
if (array[i] === 0) {
index = i;
counter ;
} else {
if (counter !== 0) {
result.push([index - counter 1, index]);
counter = 0;
}
}
}
if (counter !== 0) { result.push([index - counter 1, index]); }
return result;
}
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
//[[0,4], [9, 11], [17, 18], [21, 25], [27, 27]]
let zeroes = findZerosSequences(sequence);
for(let i = 0; i < zeroes.length; i ){
let lf = sequence[zeroes[i][0] - 1];
let rf = sequence[zeroes[i][1] 1];
if(lf !== undefined && rf !== undefined && lf > 0 && rf > 0){
interpolateValues(sequence, zeroes[i][0], zeroes[i][1], lf, rf);
}
}
console.log(sequence);
let output = [
12, 12, 12, 12, 12,
12, 64, 9, 6,
10.75, 15.5, 20.25,
25, 79, 57, 13, 39,
28.3333, 17.6666,
7, 7,
14, 21, 28, 35, 42,
49,
49
];
CodePudding user response:
You almost got it, let the interpolateValues
worry about those edge cases which are easily resolved.
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
const interpolateValues = (array, index0, index1, left, right) => {
if (left === null) left = right;
if (right === null) right = left;
if (left === null && right === null) left = right = 0;
let n = index1 - index0 1;
let step = (right - left) / (n 1);
for (let i = 0; i < n; i ) {
array[index0 i] = left step * (i 1);
}
}
const findZerosSequences = (array) => {
var counter = 0;
var index = 0;
var result = [];
for (let i = 0; i < array.length; i ) {
if (array[i] === 0) {
index = i;
counter ;
} else {
if (counter !== 0) {
result.push([index - counter 1, index]);
counter = 0;
}
}
}
if (counter !== 0) {
result.push([index - counter 1, index]);
}
return result;
}
let zeroes = findZerosSequences(sequence);
for (let i = 0; i < zeroes.length; i ) {
let lf = zeroes[i][0] - 1 >= 0 ? sequence[zeroes[i][0] - 1] : null;
let rf = zeroes[i][1] 1 < sequence.length ? sequence[zeroes[i][1] 1] : null;
interpolateValues(sequence, zeroes[i][0], zeroes[i][1], lf, rf);
}
console.log(sequence);
CodePudding user response:
If anyone would be interested in spaghetti instead of a valid answer :)
const sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
]
const output = sequence.join(',')
.replace(/^([0,] )(\d )/, (_, zeros, number) => {
const n = zeros.match(/0/g).length
return (number ',').repeat(n) number
})
.replace(/([^0,] ),([0,] )([^0,] )/g, (_, number1, zeros, number2) => {
const n = zeros.match(/0/g).length
const diff = number2 - number1
const step = diff / (n 1)
return number1 ',' [...Array(n).keys()].map(i => {
const val = number1 (i 1) * step
return Math.floor(val * 10000) / 10000
}) ',' number2
})
.replace(/(\d )([,0] )$/, (_, number, zeros) => {
const n = zeros.match(/0/g).length
return number (',' number).repeat(n)
}).split(',').map(Number);
console.log(output)
CodePudding user response:
I would keep track of the start and end values when looping over looking for non zeros. When it is the start the starting index will not be set so you know it needs to be the first value. You can loop one extra index and you know it will be the end. For the others it will be the step like you did.
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let startIndex = -1;
for (var i = 0; i <= sequence.length; i ) {
if (sequence[i] !== 0) {
if (i - startIndex > 1) {
let func;
const startVal = sequence[startIndex];
const endVal = sequence[i];
if (startIndex === -1) {
func = () => endVal;
} else if (i === sequence.length) {
func = () => startVal;
} else {
func = (j) => {
return startVal (endVal - startVal) / (i - startIndex) * j;
}
}
for (let j = 1; j < i - startIndex; j ) {
sequence[j startIndex] = func(j);
}
}
startIndex = i;
}
}
console.log(sequence);
Other way is set the start and end and do the calculation
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let startIndex = -1;
for (var i = 0; i <= sequence.length; i ) {
if (sequence[i] !== 0) {
if (i - startIndex > 1) {
const startVal = startIndex === -1 ? sequence[i] : sequence[startIndex];
const endVal = i === sequence.length ? startVal : sequence[i];
const func = (j) => {
return startVal (endVal - startVal) / (i - startIndex) * j;
}
for (let j = 1; j < i - startIndex; j ) {
sequence[j startIndex] = func(j);
}
}
startIndex = i;
}
}
console.log(sequence);
CodePudding user response:
Haven't checked my sample, but you should see the way I guess..
let sequence = [
0, 0, 0, 0, 0,
12, 64, 9, 6,
0, 0, 0,
25, 79, 57, 13, 39,
0, 0,
7, 7,
0, 0, 0, 0, 0,
49,
0
];
let temporaryZerosArray = [];
for (const [id, value] of sequence.entries()) {
if (value) {
if (!temporaryZerosArray.length) continue;
temporaryZerosArray.splice(0, temporaryZerosArray.length - 2);
let [one, two] = temporaryZerosArray;
let lf = sequence[one-1]
let rf = sequence[two 1]
if (
(!!lf && lf > 0) &&
(!!rf && rf > 0)
) interpolateValues(sequence, one,two, lf , rf );
temporaryZerosArray = [];
continue
}
temporaryZerosArray.push(id);
}
CodePudding user response:
Here's a solution that accepts your input array and returns the interpolated output array. I put comments inline with the code to explain how it works. This solution also behaves correctly for arrays of all zeros.
function interpolateArray(input) {
let output = []; // New array for output
let zeros = 0; // Count of sequential zeros
let start = 0; // Starting number for interpolation
for (let i = 0; i < input.length; i ) { // Loop through all input values
let value = input[i]; // Current input value
if (value === 0) zeros ; // If value is zero, increment the zero count
else { // If the value is non-zero...
if (start === 0) start = value; // If the starting value is zero, set start to current non-zero value
if (zeros) { // If there are zeros accumulated...
let step = (value - start) / (zeros 1); // Compute the step value (current value, minus start, divided by total steps)
for (let j = 1; j <= zeros; j ) output.push(start (j * step)); // For each zero, push the stepped value to output
zeros = 0; // Reset zero count
}
start = value; // Store the current value as the new start
output.push(start); // Push the current non-zero value to output
}
}
for (let j = 0; j < zeros; j ) output.push(start); // If there are accumulated zeros, that means they were trailing. Push last non-zero value to output for each
return output; // Return the output
}
Update:
Just for fun, I tightened up the code a bit so the function is more compact. It works exactly the same.
function interpolateArray(input) {
let output = [], zeros = 0, start = 0;
input.forEach(value => {
if (value) {
start = start || value;
if (zeros) {
let step = (value - start) / (zeros 1);
while (zeros--) output.push(start = step);
zeros = 0;
}
output.push(start = value);
} else zeros ;
});
while (zeros--) output.push(start);
return output;
}