【问题标题】:Combine two arrays of objects into one array for use in Google Charts将两个对象数组合并为一个数组以在 Google 图表中使用
【发布时间】:2017-10-03 10:49:10
【问题描述】:

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

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

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,因为我知道它对这些类型的问题有一些很好的实用功能,但我就是没能解决它(说实话,没有太多经验)和我知道这里有人比我知识渊博,所以我正在寻求帮助。

提前感谢您抽出宝贵时间回答这个问题。

附:我会链接到 Moment.js,但目前我没有足够的声誉来发布超过 2 个链接。

【问题讨论】:

  • 不管怎样,我真的不明白你想要做什么......我猜是直方图之类的东西?
  • @YvonneReinhardt 不,只是连接数组不是我要找的东西。查看我链接到的谷歌图表文档中的示例。不完全是直方图,而是我想说的价值时间线。您可以在金融图表上找到一些东西,例如您可以在一段时间内看到美元/欧元的价值。

标签: javascript arrays object google-visualization underscore.js


【解决方案1】:

建议从数组中创建两个谷歌数据表...

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
其他图表,您可以保留空值

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

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

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

请参阅以下工作 sn-p...

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”,因为它是一个时间线,值不会下降到零。但是,非常感谢你,我自己永远不会这样做。
【解决方案2】:

可能无法直接回答您的问题,但您有没有想过使用时间戳作为对象键?像这样使用它比在为现有对象分配新值时循环它要高效得多。

例如

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 已经给出了他的答案,这实际上是对我问题的直接回答。
猜你喜欢
  • 1970-01-01
  • 2017-04-24
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
  • 2015-10-11
相关资源
最近更新 更多