将 JSON 转换为数组以在 C3 中绘制时间序列的更好方法?

Better way to convert JSON to arrays for graphing timeseries in C3?

我正在努力将一些 JSON 数据转换成一种格式,该格式可用于在 C3 中绘制时间序列图,它采用数组数组作为列输入。我有我独特的 x 值数组,但我想不出一个很好的方法来获取我的 y 值。完成此操作后,我需要将 y2 与 numSold 相加,但我想如果我能解决这个问题,我就能解决这个问题。

这是我需要的数据的最终格式:

[
  ["x", "9-2-17", "9-4-17", "10-2-17"],
  ['item1-cost', 100, 150, 10],
  ['item3-cost', 200, null, 20],
  ...
]

没有固定的日期数或固定的项目数。这是我从数据库中读取的任何内容。项目编号不一定是连续的。我们只关心为我们拥有数据的项目绘制数据图表。但是不会有每个日期项目组合的数据。当发生这种情况时,我需要插入一个 null 以指示该项目没有该日期的数据。商品编号为 1 索引。

除了普通的 JavaScript 函数之外,我可以使用 lo-dash 或 D3 中的任何东西来解决这个问题,但我正在努力避免难以阅读的代码和低效的代码。我觉得其他人一定有这个需求,而且一定有某种功能,比如我应该使用的过滤功能。

我当前的实现没有我想要的那么高效,而且有点难以阅读。我使用项目编号作为索引并制作一个稀疏数组,稍后我必须对其进行压缩。这是伪代码:

For every d object in data
  For the i index of d.date in uniqueDates
    If values[d.item] is undefined
      Fill values[d.item]] with null for uniqueDates.length
    Set values[d.item][i] to d.cost
Convert values to dense format for graphing

这是我正在玩的Fiddle的link:

https://jsfiddle.net/dbkidd/q3r3moqu/

var data = [
  {date: '9-2-17', item: 1, cost: 100},
  {date: '9-2-17', item: 3, cost: 200},
  {date: '9-4-17', item: 1, cost: 150},
  /* '9-4-17' does not have an entry for item 3 so cost should be counted as null */
  {date: '10-2-17', item: 1, cost: 10},
  {date: '10-2-17', item: 3, cost: 20}
]

var uniqueDates = _.uniq(_.flatMap(data, 'date'));
uniqueDates.unshift('x');

var values = [];
values.push(uniqueDates);

function getLabel(index) {
  return 'item' + index + '-' + 'cost';
}

for (var d = 0; d < data.length; d++) {
  var i = _.indexOf(uniqueDates, data[d].date);
  if (data[d].item !== undefined) {
    var item = data[d].item;
    if (values[item] === undefined) {
        values[item] = _.fill(Array(uniqueDates.length), null);
        values[item][0] = getLabel(item);
    }
    values[item][i] = data[d].cost;
    }
}

function checkIfUndefined(x) {
    return (x !== undefined);
}

function sparseToDense(data) {
  return data.filter(checkIfUndefined);
}

values = sparseToDense(values);

我对这个问题很感兴趣,并提出了第一个版本。它与您的略有不同,但在这里。我会注意到我没有尝试对日期进行排序或将项目重命名为有用的东西,但可以添加这些。

var data = [
 {date: '9-2-17', item: 1, cost: 100},
  {date: '9-2-17', item: 3, cost: 200},
  {date: '9-4-17', item: 1, cost: 150},
  /* '9-4-17' does not have an entry for item 3 so cost should be counted as null */
  {date: '10-2-17', item: 1, cost: 10},
  {date: '10-2-17', item: 3, cost: 20},
  {date: '10-3-17', item: 2, cost: 2000}
]

// utility functions
const product = (...sets) =>
  sets.reduce((acc, set) =>
    _.flatten(acc.map(x => set.map(y => [ ...x, y ]))),
    [[]]);

// the meat and potatoes
const builder = lookup => pairs => pairs.reduce((agg, [item, date]) => {
   const out = _.cloneDeep(agg);
   const value = _.get(lookup, [date, item, 'cost'], null);
   const evalue = _.get(out, date, []);
   evalue.push(value);
   _.set(out, date, evalue);
   return out;
}, {})

// setup data structures for searching
const byDateByItem = _.mapValues(_.groupBy(data, 'date'), x => _.keyBy(x, 'item'));    
const items = _.uniq(data.map(x=>x.item));
const dates = _.uniq(data.map(x=>x.date));

// create all posibilities
const pairs = product(items, dates);
// populate possibilities with values
const hash = builder(byDateByItem)(pairs);
// put keys with values in their respective lists
const p = _.toPairs(hash).map(_.flatten);
// smash data into a matrix type thing
const table = [['x',...items], ...p];
// flip the table on it's side (╯°□°)╯︵ ┻━┻
const out = _.zip(...table);
console.log('out', out);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>