首页 > 解决方案 > 如何通过函数式编程在一个公共键上合并 N 个元组数组?

问题描述

我有 3 个数组,它们都包含元组。第一个值是时间戳 (ts),第二个是当时发生的事件计数。单个数组根据时间戳进行排序。

var arr1 = [{ts: 1000, val: 1},{ts: 1001, val: 2},{ts: 1002, val: 3}];
var arr2 = [{ts: 1001, val: 4},{ts: 1002, val: 5},{ts: 1005, val: 6}];
var arr3 = [{ts: 1003, val: 8},{ts: 1007, val: 8},{ts: 1008, val: 8}];

我想将它们合并到一个时间线中,在一个 4xN 数组中,这样它就变成了:

[
    [1000, 1, 0, 0],
    [1001, 2, 4, 0],
    [1002, 3, 5, 0],
    [1003, 0, 0, 8],
    [1005, 0, 6, 0],
    [1007, 0, 0, 8],
    [1008, 0, 0, 8],
]

其中第一列是时间戳,第二列是第一个数组值,第三列是第二个数组值...

我试图以非功能性的方式来做,但无法提出一个优雅清晰的解决方案,它不涉及重复查找数组中的时间戳以找到相应的值。我觉得应该有一种相对简单的方法可以在功能上做到这一点,因为我基本上是将基于行的数据转换为列式数据。

如果为 N 个数组解决它是有问题的,我也可以使用 3 个数组的解决方案!

标签: javascriptarraysfunctional-programmingramda.js

解决方案


我没有看到比您丢弃的在数组中查找时间戳的概念更好的了。如果数据真的很大,那么您可以对其进行索引。但是代码不太可能是漂亮的。

这是一个 ES6 版本:

const extract = (...xss) => 
  [... new Set (xss .flatMap (xs => xs .map (x => x .ts)))]
    .map (t => [t, ... xss .map (xs => (xs.find(({ts}) => t == ts) || {val: 0}).val)])


const arr1 = [{ts: 1000, val: 1}, {ts: 1001, val: 2}, {ts: 1002, val: 3}];
const arr2 = [{ts: 1001, val: 4}, {ts: 1002, val: 5}, {ts: 1005, val: 6}];
const arr3 = [{ts: 1003, val: 8}, {ts: 1007, val: 8}, {ts: 1008, val: 8}];

console .log (extract (arr1, arr2, arr3))
.as-console-wrapper {max-height: 100% !important; top: 0}

至于 Ramda,我们当然可以在这里使用 Ramda。第一行可以替换为

  uniq (chain (pluck ('ts')) (xss))

我们可以类似地用 Ramda 等价物替换maps 和,我们可以用 a代替. 如果您使用 Ramda,您可能可以继续这种方式一段时间,我强烈建议您尝试一下。但我认为,如果您正在寻找一个完全无点的解决方案,它很可能很快就会变得不可读。finddefaultTo|| {val: 0}


推荐阅读