我有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个阵列的解决方案!
我认为没有什么比您放弃的在数组中查找时间戳的概念更好的了。如果数据真的很大,那么你可以对它进行索引。但代码可能不太漂亮。
这是一个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}
至于拉姆达,我们当然可以在这里使用拉姆达。第一条线路可以用代替
uniq (chain (pluck ('ts')) (xss))
我们可以类似地用Ramda等价物代替map
和find
,并且我们可以用defaultTo
代替|| {val: 0}
。如果你正在使用Ramda,你可能会继续这种方式一段时间,我敦促你尝试一下。但我认为,如果你正在寻找一个完全无点的解决方案,它很可能会很快变得不可读。
展平数组,同时将原始数组的索引添加到每个项。然后,按ts
分组,将每个对象数组缩减为数字数组,将密钥(原始ts
(添加到每个数组,并转换为具有R值的数组:
const { addIndex, map, pipe, chain, groupBy, prop, reduce, set, lensIndex, mapObjIndexed, values } = R;
const mapIndexed = addIndex(map);
const fill0 = map(() => 0);
const extract = (...xss) => pipe(
chain(mapIndexed((o, idx) => ({ ...o, idx }))), // add column index to each object
groupBy(prop('ts')),
map(reduce((acc, { idx, val }) => set(lensIndex(idx), val, acc), fill0(xss))), //fill the numbers in the index place
mapObjIndexed((vals, k) => [k, ...vals]), // create the row array
values
)(xss)
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}];
const result = extract(arr1, arr2, arr3);
console.log(result);
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>
使用vanillaJS,您可以将数组的数组简化为Map,如果Map中不存在键,则迭代每个数组的值,将数组设置为0,并更新相关索引处的值。使用Array.from()
将Map的条目转换为行数组:
const extract = (...xss) => Array.from(
xss.reduce((acc, o, i) => {
o.forEach(({ ts, val }) => { // iterate each array
if (!acc.has(ts)) acc.set(ts, [...xss].fill(0)); // if the key (ts) doesn't exist set it as an array of 0s
acc.get(ts)[i] = val; // replace the 0 with a value
});
return acc;
}, new Map())
).map(([k, values]) => [k, ...values]); // convert the Map to an array of arrays
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}