简体   繁体   中英

Convert JSON data into format in Highcharts' basic line chart

Using Javascript, I am trying to convert some JSON data into the format used in Highcharts' basic line chart.

What I have to start with:

originalArray = [
    ['valueA', 1],
    ['valueA', 0],
    ['valueB', 9],
    ['valueB', 9],
    ['valueB', 3],
    ['valueC', 11]
]

And what I'm trying to create using the above:

desiredArray = [{
      name: 'valueA',
      data: [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  }, {
    name: 'valueB',
    data: [0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0]
  }, {
    name: 'valueC',
    data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
  }]

For some additional context, the 0-11 in originalArray[i][1] references a month (0 = January), and the desiredArray is a list of unique names and a count of their occurrences by month.

So far, I can:

  • Convert the data into a new array of objects
  • For each unique name in originalArray
    • Create a new object in the desiredArray , and set the name attribute
    • Add a data attribute that contains an empty array

But then I run into trouble, and can't figure out how to:

  • Loop through the originalArray
    • If the name in the originalArray matches the name in the desiredArray
      • Increment a counter in the matching seriesArray[i].data array, using the value of originalArray[i][1] as the index (it always be 0-11).

So I'm asking:

  1. What's a good way to iterate across my originalArray , match up unique values, and then act only on those matches to push to the desiredArray .
  2. What's the best way to increment the counters in desiredArray[i].data

I'm open to using libraries, such as underscore.js. Have been trying to figure this out for a couple of days now, so pretty much anything goes within the bounds of Javascript.

Updated with proper array initialization, now.

var max = originalArray.reduce(function(p,c){return Math.max(p,c[1]);},0);

var initSums = function(size) {
    var arr = new Array(size);
    for (var i=0;i<size;i++)
        arr[i]=0;
    return arr;
}

var map = originalArray.reduce(function(sums,val){
    if (!sums.hasOwnProperty(val[0])) {
        sums[val[0]] = initSums(max+1);   
    }
    sums[val[0]][val[1]]++;
    return sums;
},{});

var desiredArray = Object.keys(map).map(function(key) {
    return {name: key, data: map[key]}; 
});

What we're doing here is a multi-step process:

  1. Decide how big our arrays are going to need to be, by first scanning for the largest value in the original array.

  2. Use an object to aggregate the counts (using Array.reduce() ).

  3. Transform the object and its properties into an array of name/data pair objects (using Array.map ).

Edit : An improvement on S McCochran's solution, skipping the extraneous search for the maximum value in originalArray , since there should always be 12 elements of each data array, one per month.

function formatForHighcharts(array) {

  // Create a map from value name to array of month counts
  var map = originalArray.reduce(function(sums, pair) {
    var key = pair[0], val = pair[1];

    if(!(key in sums))
      sums[key] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

    // val is the month index, which corresponds directly to array index, so increase that
    sums[key][val]++;

    return sums;
  }, {});

  // Map the object to an array of { name: ..., data: ... } pairs
  var formatted = Object.keys(map).map(function (key) {
    return { name: key, data: map[key] };
  });

  return formatted;
}

Usage:

var desiredArray = formatForHighcharts(originalArray);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM