将两个对象数组合并为一个数组以用于 Google 图表

Combine two arrays of objects into one array for use in Google Charts

在我开始之前,是的,我疯狂地用谷歌搜索并阅读了很多关于 SO 的答案,但我无法完成需要完成的事情,所以我正在寻求帮助。

我有一个我无法解决的问题。我必须在 Google 注释图表中显示一些数据。我得到的数据是这种格式:

var arr1 = [{
    timestamp: "1505735024496", value1: 2
},
{
    timestamp: "1505815355920", value1: 5
},
.....
]

var arr2 = [{
    timestamp: "1505383687151", value2: 1
},
{
    timestamp: "1505485417374", value2: 3
},
.....
]

这里的最终目标是将这两个对象数组组合成一个数组数组,如下所示:

var final = [
[new Date(YYYY, DD, MM), value1, value2], 
[new Date(YYYY, DD, MM), value1, value2], 
...
]

根据特定图表 Google Charts documentation 上的说明。

我只设法将时间戳转换为具有这些日期的相应值的完整日期,但这又给了我一个对象数组,我只是将时间戳转换为日期而没有太大变化。

var indexesArr1 = arr1.map(function (obj) {
  return obj.timestamp;
});

var arr1New = arr1.map(function (obj) {
  var index = indexesArr1.indexOf(obj.timestamp);
  return { date: moment(parseInt(obj.timestamp)).format('YYYY, MM, DD'), value1: index > -1 ? arr1[index].value : obj.value };
});

这里真正的问题是 arr1 和 arr2 不必具有相同的长度(并且可能不会在大多数时间相同)并且由于此图表将随时间显示数据,因此重要的是填充每个具有 value1 和 value2 的日期,甚至认为可能不会为该特定日期显式返回其中一个值。还有一件事是删除重复日期的所有实例,但保留最后一个,因为那个代表该特定日期的最后一个记录值。

我已经使用 Moment.js 轻松地将时间戳转换为所需的格式 ('YYYY, DD, MM'),但我无法正确地进行所有数据操作。

允许使用 Underscore.js,因为我知道它对这类问题有一些很好的实用功能,但我就是无法解决它(没有太多经验老实说)我知道这里有人比我知识渊博,所以我正在寻求帮助。

预先感谢您花时间回答这个问题。

P.S。我会 link 到 Moment.js 但我没有足够的声誉 post 目前超过 2 links。

建议从数组中创建两个 google 数据 table...

var arr1 = [{
  timestamp: "1505735024496", value1: 1
}, {
  timestamp: "1505735034496", value1: 2
}, {
  timestamp: "1505815355920", value1: 5
}];

var arr2 = [{
  timestamp: "1505383687151", value2: 1
}, {
  timestamp: "1505485417374", value2: 3
}];

var data1 = google.visualization.arrayToDataTable(arr1.map(function (row) {
  return [new Date(parseInt(row.timestamp)), row.value1];
}), true);

var data2 = google.visualization.arrayToDataTable(arr2.map(function (row) {
  return [new Date(parseInt(row.timestamp)), row.value2];
}), true);

然后你可以在时间戳

上加入数据 tables
var dataJoin = google.visualization.data.join(
  data1,
  data2,
  'full',
  [[0, 0]],
  [1],
  [1]
);

联接将为日期不匹配的每一列使用 null 值,
可以使用数据视图将其替换为零

AnnotationChart 不支持选项 interpolateNulls,
其他图表,您可以保留空值

解决遗漏日期和多个日期的问题,
使用数据 table 方法 getColumnRange 查找 table

中的最小和最大日期

然后从最小日期开始,直到最大日期,
使用数据 table 方法 getFilteredRows 检查
之间的每个日期 仅使用日期部分,删除时间值

如果日期不存在,添加一个新行
如果日期存在多次,删除除最后一个以外的所有

请参阅以下工作片段...

google.charts.load('current', {
  packages: ['annotationchart', 'table']
}).then(function () {

  // date formatter
  var formatDate = new google.visualization.DateFormat({
    pattern: 'yyyy-MM-dd'
  });

  // original arrays
  var arr1 = [{
    timestamp: "1505735024496", value1: 1
  }, {
    timestamp: "1505735034496", value1: 2
  }, {
    timestamp: "1505815355920", value1: 5
  }];
  var arr2 = [{
    timestamp: "1505383687151", value2: 1
  }, {
    timestamp: "1505485417374", value2: 3
  }];

  // create google data table for each array
  var data1 = google.visualization.arrayToDataTable(arr1.map(function (row) {
    return [new Date(parseInt(row.timestamp)), row.value1];
  }), true);
  var data2 = google.visualization.arrayToDataTable(arr2.map(function (row) {
    return [new Date(parseInt(row.timestamp)), row.value2];
  }), true);

  // join data tables
  var dataJoin = google.visualization.data.join(
    data1,
    data2,
    'full',
    [[0, 0]],
    [1],
    [1]
  );
  // sort join data table to ensure latest date is last
  dataJoin.sort([{column: 0}]);

  // one day time
  var oneDay = (1000 * 60 * 60 * 24);

  // get date range
  var dateRange = dataJoin.getColumnRange(0);

  // drop time values from min and max dates
  var begDate = new Date(dateRange.min.getFullYear(), dateRange.min.getMonth(), dateRange.min.getDate());
  var endDate = new Date(dateRange.max.getFullYear(), dateRange.max.getMonth(), dateRange.max.getDate());

  // check each date
  for (var iDate = begDate.getTime(); iDate <= endDate.getTime(); iDate = iDate + oneDay) {
    // find date
    var findDate = new Date(iDate);
    var dateRows = dataJoin.getFilteredRows([{
      column: 0,
      test: function (rowValue) {
        var rowDate = formatDate.formatValue(rowValue);
        var testDate = formatDate.formatValue(findDate);
        return (rowDate === testDate);
      }
    }]);

    // getFilteredRows will return array of row indexes
    switch (dateRows.length) {
      // add row
      case 0:
        dataJoin.addRow([findDate, null, null]);
        break;

      case 1:
        break;

      // remove all duplicates except the last row index found
      default:
        for (var iRow = dateRows.length - 2; iRow >= 0; iRow = iRow - 1) {
          dataJoin.removeRow(dateRows[iRow]);
        }
    }
  }
  dataJoin.sort([{column: 0}]);

  // replace null values with zeroes
  var dataView = new google.visualization.DataView(dataJoin);
  dataView.setColumns([0, {
    calc: function (dt, row) {
      return dt.getValue(row, 1) || 0;
    },
    label: 'y0',
    type: 'number'
  }, {
    calc: function (dt, row) {
      return dt.getValue(row, 2) || 0;
    },
    label: 'y1',
    type: 'number'
  }]);

  // draw annotation chart
  var containerChart = document.getElementById('chart_div');
  var chart = new google.visualization.AnnotationChart(containerChart);
  chart.draw(dataView);

  // draw table for testing purposes, "see" the data
  var containerTable = document.getElementById('table_div');
  var table = new google.visualization.Table(containerTable);
  table.draw(dataView);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
<div id="table_div"></div>

可能无法直接回答您的问题,但您是否考虑过使用时间戳作为对象键?在为现有对象分配新值时,这样使用它比循环使用它会更高效。

例如

let obj1 = {
    '34123812371293': 2,
  '12314981391230': 3,
}
let obj2 = {
    '13812381238123' : 1,
    '19312930812930' : 3,
  '12314981391230': 100,
}

let combinedObj = Object.assign({}, obj1);
Object.keys(obj2).map(o2 => {
    if(combinedObj[o2] != undefined){
    combinedObj[o2] += obj2[o2];
  }else{
    combinedObj[o2] = obj2[o2];
  }
});
console.log(combinedObj);

这样,当您引入新数据时,您可以直接将新数据对象键与现有对象进行比较并增加值或添加新键对。

https://jsfiddle.net/z23xeaxm/