Jorman Franzini
Jorman Franzini

Reputation: 339

Javascript fill array with intermediate value

I'm trying to fill an array with missing intermediate data

My data input is like this

var data = [[5.23,7],[5.28,7],[5.32,8],[5.35,8]];

I wanna fill the array with missing value but I need to respect this rule:

  1. The 1st value on 2d array must be the next sequence number, so 5.23 ... 5.24 ... 5.25 ...
  2. The 2nd value on 2d array must be the same element from the i+1 value

So the results in this case would be

var data = [[5.23,7],[5.24,7],[5.25,7],[5.26,7],[5.27,7],[5.28,7],[5.29,8],[5.30,8],[5.31,8],[5.32,8],[5.33,8],[5.34,8],[5.35,8]];

This little piece of code works, but I don't know how to put in loop and how to write a while loop that pass every time the new length of the array

var data = [[5.23,7],[5.28,7],[5.32,8],[5.35,8]];

if (data[1][0]-data[0][0] > 0.01) {
    data.push([data[0][0]+0.01,data[1][1]]);
    data.sort(function (a, b) { return a[0] - b[0]; });
} else {
    check the next element
}

console.log(data);

Any idea?

Upvotes: 0

Views: 593

Answers (3)

Steve Ladavich
Steve Ladavich

Reputation: 3562

Here's another idea... I thought it might feel more natural to loop through the sequence numbers directly.

Your final array will range (in this example) from 5.23 to 5.35 incrementing by 0.01. This approach uses a for loop starting going from 5.23 to 5.35 incrementing by 0.01.

key points

  • Rounding: Work in x100 then divide back down to avoid floating point rounding issues. I round to the neared hundredth using toFixed(2) and then converting back to a number (with leading + operator).
  • Indexing: Recognizing 5.23 is the zero index with each index incrementing 1/100, you can calculate index from numerical values, ex. 100*(5.31-5.23) equals 8 (so 5.31 belongs in output[8]).
  • 2nd values: given a numerical value (ex. 5.31), just find the first element in the data array with a higher 1st value and use its 2nd value - this is a corollary of your requirement. Because 5.31 <= 5.28 is false, don't use 7 (from [5.28,7]). Because 5.31 <= 5.32 is true, use 8 (from [5.32,8]).

EDIT

I improved the performance a bit - (1) initialize output instead of modifying array size, (2) work in multiples of 100 instead of continuously rounding from floating point to hundredths.

I ran 5000 iterations on a longer example and, on average, these modifications make this approach 3x faster than Redu's (where the original was 2x slower).

var data = [[5.23,7],[5.28,7],[5.32,8],[5.35,8]];

var output = Array((data[data.length-1][0]-data[0][0]).toFixed(2)*100+1)

function getIndex(value){
   return (value-data[0][0]*100)
}
  
for( var i = 100*data[0][0]; i <= 100*data[data.length-1][0]; i++ ){
  output[getIndex(i)] = [i/100, data.find( d => i <= 100*d[0] )[1]]
}

//console.log(output)





// Performance comparison
function option1(data){
  let t = performance.now()

  var output = Array((data[data.length-1][0]-data[0][0]).toFixed(2)*100+1)

  function getIndex(value){
     return (value-data[0][0]*100)
  }
  
  for( var i = 100*data[0][0]; i <= 100*data[data.length-1][0]; i++ ){
    output[getIndex(i)] = [i/100, data.find( d => i <= 100*d[0] )[1]]
  }

  return performance.now()-t
}

function option2(data){
  let t = performance.now()
  
  newData = data.reduce((p,c,i,a) => i ? p.concat(Array(Math.round(c[0]*100 - a[i-1][0]*100)).fill()
                                                                                            .map((_,j) => [Number((a[i-1][0]+(j+1)/100).toFixed(2)),c[1]]))
                                      : [c],[]);
  return performance.now()-t
}

var testdata = [[1.13,4],[2.05,6],[5.23,7],[5.28,7],[5.32,8],[5.35,8],[8.91,9],[10.31,9]];
var nTrials = 10000;

for(var trial=0, t1=0; trial<=nTrials; trial++) t1 += option1(testdata)
for(var trial=0, t2=0; trial<=nTrials; trial++) t2 += option2(testdata)

console.log(t1/nTrials) // ~0.4 ms
console.log(t2/nTrials) // ~0.55 ms

Upvotes: 1

Redu
Redu

Reputation: 26161

Array.prototype.reduce() is sometimes handy to extend the array. May be you can do as follows;

var data = [[5.23,7],[5.28,7],[5.32,8],[5.35,8]],
 newData = data.reduce((p,c,i,a) => i ? p.concat(Array(Math.round(c[0]*100 - a[i-1][0]*100)).fill()
                                                                                            .map((_,j) => [Number((a[i-1][0]+(j+1)/100).toFixed(2)),c[1]]))
                                      : [c],[]);
console.log(newData);

var data = [[1.01,3],[1.04,4],[1.09,5],[1.10,6],[1.15,7]],
 newData = data.reduce((p,c,i,a) => i ? p.concat(Array(Math.round(c[0]*100 - a[i-1][0]*100)).fill()
                                                                                            .map((_,j) => [Number((a[i-1][0]+(j+1)/100).toFixed(2)),c[1]]))
                                      : [c],[]);
console.log(newData);

Upvotes: 1

kevin ternet
kevin ternet

Reputation: 4612

I propose this solution :

var data = [[5.23,7],[5.28,7],[5.32,8],[5.35,8]];
var res = [];
data.forEach((item, index, arr) => {
   res.push(item);
   var temp = item[0];
   while (arr[index+1] && arr[index+1][0]-temp > 0.01){
      temp += 0.01;
      res.push([temp, arr[index+1][1]]);
   }
});
console.log(res); 

Upvotes: 0

Related Questions