将两个对象数组合并为一个数组以在Google Charts中使用

3

在我开始之前,是的,我疯狂地谷歌搜索并阅读了许多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文档上的说明操作。
我只能将时间戳转换为相应日期的完整日期,但这又给了我一个对象数组,在这个数组中,我只是将时间戳转换为日期,没有太多变化。
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. 我会链接到Moment.js,但我目前没有足够的声望发布超过2个链接。


这里https://www.w3schools.com/jsref/jsref_concat_array.asp有帮助吗? - KayleeTheMech
无论如何,我真的不明白你想做什么... 我猜是类似于直方图? - KayleeTheMech
@YvonneReinhardt 不,仅仅连接数组并不是我要找的东西。看一下我链接到的谷歌图表文档中的示例。虽然不完全是直方图,但我会说它是值时间线。例如,在金融图表中可以看到随着时间推移USD/EUR的价值。 - Marko Hologram
2个回答

1
建议从数组中创建两个 Google 数据表...
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);

然后,您可以根据时间戳将数据表进行连接。
var dataJoin = google.visualization.data.join(
  data1,
  data2,
  'full',
  [[0, 0]],
  [1],
  [1]
);

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

AnnotationChart不支持选项interpolateNulls
对于其他图表,您可以保留null

为了解决缺失和多个日期问题,
使用数据表方法getColumnRange查找表中的最小和最大日期

然后从最小日期开始,直到最大日期,
使用数据表方法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>


真的,你是救命恩人。它有效了。现在我只需要研究一下,将那些具有value1/value2值为“0”的日期填充为前一天的值,因为这是一个时间线,值不会突然降为零。但还是非常感谢你,我自己永远做不到这一点。 - Marko Hologram

0
也许不是直接回答你的问题,但你有没有想过将时间戳作为对象键?这样使用会比在给现有对象分配新值时循环更高效。例如:
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/


谢谢您的回复,我会记住的,但是@WhiteHat已经给出了他的答案,这实际上是对我的问题的直接回答。 - Marko Hologram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接