代码之家  ›  专栏  ›  技术社区  ›  SkyWalker

在JavaScript中,合并日期-时间序列的有效算法是什么?

  •  -1
  • SkyWalker  · 技术社区  · 1 年前

    我有以下时间序列列表作为输入:

    const ts1 = [
      ['2023-01-20', 1],
      ['2023-01-21', 2],
      ['2023-01-22', 3],
      ['2023-01-23', 4],
    ];
    
    const ts2 = [
      ['2023-01-18', 5],
      ['2023-01-19', 6],
      ['2023-01-20', 7],
      ['2023-01-21', 8]
    ];
    
    const ts3 = [
      ['2023-01-21', 9],
      ['2023-01-22', 10],
      ['2023-01-23', 11],
      ['2023-01-24', 12]
    ];
    

    我希望输出是合并的(列堆叠的)版本,如下所示:

    const output = [
      ['2023-01-18', null,    5, null],
      ['2023-01-19', null,    6, null],
      ['2023-01-20',    1,    7, null],
      ['2023-01-21',    2,    8,    9],
      ['2023-01-22',    3, null,   10],
      ['2023-01-23',    4, null,   11],
      ['2023-01-24', null, null,   12]
    ];
    

    为了提供更多的上下文,我重用了一个REST API,它提供了单独的时间序列,我需要编译AnyChart所需的tableData格式。

    1 回复  |  直到 1 年前
        1
  •  0
  •   AKX Bryan Oakley    1 年前

    我会选择这样的东西

    const merged = {};
    
    let tses = [ts1, ts2, ts3];
    for (let i = 0; i < tses.length; i++) {
      for (const [t, v] of tses[i]) {
        if (!merged[t]) merged[t] = new Array(tses.length).fill(null);
        merged[t][i] = v;
      }
    }
    
    console.log(Object.entries(merged).map(([t, vs]) => [t, ...vs]));
    

    此输出

    [
      [ '2023-01-20', 1, 7, null ],
      [ '2023-01-21', 2, 8, 9 ],
      [ '2023-01-22', 3, null, 10 ],
      [ '2023-01-23', 4, null, 11 ],
      [ '2023-01-18', null, 5, null ],
      [ '2023-01-19', null, 6, null ],
      [ '2023-01-24', null, null, 12 ]
    ]
    

    正如预期的那样。

    对于排序顺序(因为键是按字典排序的),请执行

    console.log(Object.keys(merged).sort().map(key => [key, ...merged[key]]));
    

    相反:

    [
      [ '2023-01-18', null, 5, null ],
      [ '2023-01-19', null, 6, null ],
      [ '2023-01-20', 1, 7, null ],   
      [ '2023-01-21', 2, 8, 9 ],      
      [ '2023-01-22', 3, null, 10 ],  
      [ '2023-01-23', 4, null, 11 ],
      [ '2023-01-24', null, null, 12 ]
    ]
    
        2
  •  0
  •   Unmitigated    1 年前

    一种替代方法 Array#reduce nullish coalescing assignment 以下为:

    const ts1=[["2023-01-20",1],["2023-01-21",2],["2023-01-22",3],["2023-01-23",4],],ts2=[["2023-01-18",5],["2023-01-19",6],["2023-01-20",7],["2023-01-21",8]],ts3=[["2023-01-21",9],["2023-01-22",10],["2023-01-23",11],["2023-01-24",12]];
    const res = Object.entries([ts1, ts2, ts3].reduce((acc, curr, i, t) => {
      curr.forEach(([k, v]) => (acc[k] ??= Array(t.length).fill(null))[i] = v);
      return acc;
    }, {})).sort().map(([k, v]) => [k, ...v]);
    console.log(res);
        3
  •  0
  •   suchislife    1 年前

    您可以创建一种高效的算法来合并时间序列,方法是首先将所有日期和值放在哈希图中,然后将其转换为数组。

    这是一种有效的方法,因为哈希映射操作(插入和查找)通常为O(1),这使得算法比直接比较和插入数组更快。

    以下是一个示例:

    const ts1 = [
      ['2023-01-20', 1],
      ['2023-01-21', 2],
      ['2023-01-22', 3],
      ['2023-01-23', 4],
    ];
    
    const ts2 = [
      ['2023-01-18', 5],
      ['2023-01-19', 6],
      ['2023-01-20', 7],
      ['2023-01-21', 8]
    ];
    
    const ts3 = [
      ['2023-01-21', 9],
      ['2023-01-22', 10],
      ['2023-01-23', 11],
      ['2023-01-24', 12]
    ];
    
    function mergeTimeSeries(...timeSeries) {
      const hashMap = {};
      let seriesIndex = 1;
      
      for (const ts of timeSeries) {
        for (const [date, value] of ts) {
          if (!hashMap[date]) {
            hashMap[date] = Array(timeSeries.length + 1).fill(null);
            hashMap[date][0] = date;
          }
          hashMap[date][seriesIndex] = value;
        }
        seriesIndex++;
      }
    
      // Convert hashMap into array and sort by date
      const result = Object.values(hashMap).sort((a, b) => new Date(a[0]) - new Date(b[0]));
    
      return result;
    }
    
    const output = mergeTimeSeries(ts1, ts2, ts3);
    
    console.log(output);