digamos que tengo una secuencia numérica arbitraria
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 ];Necesito reemplazar todos los ceros con la interpolación dada por los vecinos que no son ceros, por lo que la salida sería
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 ];Si bien los primeros ceros [0, 4] no tienen un vecino izquierdo, todos sus valores deben ser 12, mientras que el último cero solo tiene un residente derecho 49, sería solo 49.
Para mí, realmente no es un problema llenar partes donde se presentan vecinos tanto a la izquierda como a la derecha, sin embargo, estoy buscando una solución universal y elegante para esta tarea.
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 ];Si alguien estaría interesado en los espaguetis en lugar de una respuesta válida :)
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)Casi lo tiene, deje que interpolateValues se preocupe por esos casos extremos que se resuelven fácilmente.
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);Aquí hay una solución que acepta su matriz de entrada y devuelve la matriz de salida interpolada. Puse comentarios en línea con el código para explicar cómo funciona. Esta solución también se comporta correctamente para arreglos de todos ceros.
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 }Actualizar:
Solo por diversión, ajusté un poco el código para que la función sea más compacta. Funciona exactamente igual.
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; }