Best way to merge arrays of sensor data

142 views Asked by At

I am using the AHRS library to create a sensor fused array of positional data.

From the Go Pro Telemetry data I have accelerometer, gyroscope and magnetometer data arrays, with a timestamp for each sample with the shape:

{
  ACCEL: {
     samples: [{time, data}, ...]
  },
   ....
}

I want to merge these into an object

{
  time: {accel, gyro, magn}
  ...
}

With all 3 values for each timestamp

I've kind of got it working with reducers

const magn = result[1].streams['MAGN'].samples.reduce((prev, next) => {
    return {...prev, [next.cts]: {magn: next.value}}
}, {})

const gyro = result[1].streams['GYRO'].samples.reduce((prev, next) => {
    const closest = prev[Object.keys(prev).reverse()?.find(key => key < next.cts) || Object.keys(prev)[0]]
    return {...prev, [next.cts]: {...closest, gyro: next.value}}
}, magn)

const merged = result[1].streams['ACCL'].samples.reduce((prev, next) => {
    const closest = prev[Object.keys(prev).reverse()?.find(key => key < next.cts) || Object.keys(prev)[0]]
    return {...prev, [next.cts]: {...closest, accel: next.value}}
}, gyro)

But this doesn't seem like very elegant code.

Is there a more efficient way to handle it?

1

There are 1 answers

0
Gleb Shaltaev On

typescript playground

type Input = Record<string, { samples: { time: number, data: any }[] }>

type Output = Record<'number', { [K in keyof Input]: any }>

const inp: Input = { ACCEL: { samples: [{ time: 12, data: '12data' }, { time: 14, data: '14data' }]}, GYRO: { samples: [{ time: 18, data: 'gyro18' }, { time: 12, data: 'gyro12' }] }};

const keyOfInput = Object.keys(inp)

const collectionOfTimes =  [
  ... new Set(
    keyOfInput
      .map(key => inp[key].samples.map(s => s.time))
      .reduce((acc, curr) => [...acc, ...curr], []))
]

const out: Output = collectionOfTimes.reduce((acc, time) => ({ ...acc, [time]: 
  keyOfInput.reduce((acc2, key) => ({...acc2, [key]: inp[key].samples.find(i => i.time === time)?.data || null}), {})
}), {} as Output);

console.log(out);

/*
[LOG]: { "12": { "ACCEL": "12data", "GYRO": "gyro12" }, "14": { "ACCEL": "14data", "GYRO": null }, "18": { "ACCEL": null, "GYRO": "gyro18" } } 
*/

compiled to js on typescriptlang.org

"use strict";
const inp = { ACCEL: { samples: [{ time: 12, data: '12data' }, { time: 14, data: '14data' }] }, GYRO: { samples: [{ time: 18, data: 'gyro18' }, { time: 12, data: 'gyro12' }] } };
const keyOfInput = Object.keys(inp);
const collectionOfTimes = [
    ...new Set(keyOfInput
        .map(key => inp[key].samples.map(s => s.time))
        .reduce((acc, curr) => [...acc, ...curr], []))
];
const out = collectionOfTimes.reduce((acc, time) => (Object.assign(Object.assign({}, acc), { [time]: keyOfInput.reduce((acc2, key) => { var _a; return (Object.assign(Object.assign({}, acc2), { [key]: ((_a = inp[key].samples.find(i => i.time === time)) === null || _a === void 0 ? void 0 : _a.data) || null })); }, {}) })), {});
console.log(out);
/*
[LOG]: { "12": { "ACCEL": "12data", "GYRO": "gyro12" }, "14": { "ACCEL": "14data", "GYRO": null }, "18": { "ACCEL": null, "GYRO": "gyro18" } }
*/