I am processing some sensor data and my input looks something like this (the values are always 1 or 0, but the length of the values & timestamps arrays is a lot longer, as they contain the readings of a sensor for 24 hours & the data ingestion happens every second):
const input= {
values: [ 0, 1, 0, 0, 1 ],
timestamps: [
'2022-08-19T08:01:21.000Z',
'2022-08-19T08:01:22.000Z',
'2022-08-19T08:01:23.000Z',
'2022-08-19T08:01:24.000Z',
'2022-08-19T08:01:25.000Z'
]
}
or I could easily convert the input to the following format (I couldn't decide, which one would be more suitable):
const input= [{value: 0, timestamp: '2022-08-19T08:01:21.000Z'},
{value: 1, timestamp: '2022-08-19T08:01:22.000Z'},
{value: 0, timestamp: '2022-08-19T08:01:23.000Z'},
{value: 0, timestamp: '2022-08-19T08:01:24.000Z'},
{value: 1, timestamp: '2022-08-19T08:01:25.000Z'}]
My goal is to identify all the periods when the sensor reading was 0 and also validate if these periods were shorter or longer than 1 minute, i.e., for the case above, I'd like to get the following result:
result = [
{startDate: '2022-08-19T08:01:21.000Z', endDate= '2022-08-19T08:01:22.000Z', isShorterThanOneMin: true},
{startDate: '2022-08-19T08:01:23.000Z', endDate= '2022-08-19T08:01:25.000Z', isShorterThanOneMin: true}]
Could you advise a time-efficient way to solve this?
CodePudding user response:
I figured it out, not sure if it's the fastest way, but seems to work:
const input= [{value: 1, timestamp: '2022-08-19T08:01:21.000Z'},
{value: 1, timestamp: '2022-08-19T08:01:22.000Z'},
{value: 0, timestamp: '2022-08-19T08:01:23.000Z'},
{value: 0, timestamp: '2022-08-19T08:01:24.000Z'},
{value: 0, timestamp: '2022-08-19T08:01:25.000Z'},
{value: 1, timestamp: '2022-08-19T08:01:29.000Z'}]
let result = input.reduce((finalArray, currentValue,index, arr) => {
if (currentValue.value === 0) {
let resultElement = {};
resultElement.start = currentValue.timestamp;
//find end Date
let nextToCheck = index;
let endFound = false;
do {
nextToCheck = nextToCheck 1;
if (nextToCheck === arr.length) {
break;
}
if ((arr[nextToCheck].value) === 1) {
resultElement.end = arr[nextToCheck].timestamp;
endFound = true;
}
} while (!endFound)
// find out if previous one was 1 --> if it was 0, it should not be pushed to avoid having sub-arrays
if (index !== 0 && arr[index - 1 ].value !== 0) {
finalArray.push(resultElement)
}
if (index === 0) {
finalArray.push(resultElement)
}
}
return finalArray;
}, [])
console.log(result)
CodePudding user response:
Simple JavaScript version
class Processor {
constructor(inputs) {
this.inputs = inputs;
this.outputs = [];
this.process();
}
process() {
while (this.inputs.length > 0) {
const input = this.inputs.shift();
if (this.previousInput === undefined) {
this.previousInput = input.value === 0 ? input : undefined;
continue;
}
if (this.previousInput.value === 0) {
if (input.value === 0)
continue;
this.outputs.push({
startDate: this.previousInput.date,
endDate: input.date,
isShorterThanOneMinute: (input.date.getTime() - this.previousInput.date.getTime()) < 60000
});
this.previousInput = undefined;
}
}
}
}
const inputs = [
{ value: 0, date: new Date("2022-08-19T08:01:21.000Z") },
{ value: 1, date: new Date("2022-08-19T08:01:22.000Z") },
{ value: 0, date: new Date("2022-08-19T08:01:23.000Z") },
{ value: 0, date: new Date("2022-08-19T08:01:24.000Z") },
{ value: 1, date: new Date("2022-08-19T08:01:25.000Z") }
];
const processor = new Processor(inputs);
console.log(processor.outputs);
Fancier, longer TypeScript version
interface Input {
value: number;
date: Date;
}
namespace Input {
export type List = Input[];
export const clone = (input: Input): Input => {
return {
value: input.value,
date: new Date(input.date.getTime())
}
}
}
interface Output {
startDate: Date;
endDate: Date;
isShorterThanOneMinute: boolean;
}
namespace Output {
export type List = Output[];
export const clone = (output: Output): Output => {
return {
startDate: new Date(output.startDate.getTime()),
endDate: new Date(output.endDate.getTime()),
isShorterThanOneMinute: output.isShorterThanOneMinute
}
}
}
class Processor {
private previousInput?: Input;
private outputs: Output.List = [];
private inputs: Input.List;
constructor(inputs: Input.List) {
this.inputs = inputs.map(Input.clone);
this.process();
}
private process() {
while (this.inputs.length > 0) {
const input = this.inputs.shift()!;
if (this.previousInput === undefined) {
this.previousInput = input.value === 0 ? input : undefined;
continue;
}
if (this.previousInput.value === 1) {
throw new Error(`This is not possible, because we never store an input with value = 1.`);
}
if (input.value === 0) continue;
this.outputs.push({
startDate: this.previousInput.date,
endDate: input.date,
isShorterThanOneMinute: (input.date.getTime() - this.previousInput.date.getTime()) < 60000
});
this.previousInput = undefined;
}
}
getOutputs(): Output.List {
return this.outputs.map(Output.clone);
}
append(input: Input): this {
this.inputs.push(Input.clone(input));
this.process();
return this;
}
}
const inputs: Input.List = [
{ value: 0, date: new Date("2022-08-19T08:01:21.000Z") },
{ value: 1, date: new Date("2022-08-19T08:01:22.000Z") },
{ value: 0, date: new Date("2022-08-19T08:01:23.000Z") },
{ value: 0, date: new Date("2022-08-19T08:01:24.000Z") },
{ value: 1, date: new Date("2022-08-19T08:01:25.000Z") }
];
const processor = new Processor(inputs);
console.log(processor.getOutputs());
// Continue using the instance as more entries because available...
processor.append({ value: 1, date: new Date("2022-08-19T08:02:25.000Z") });
processor.append({ value: 1, date: new Date("2022-08-19T08:03:25.000Z") });
processor.append({ value: 0, date: new Date("2022-08-19T08:04:25.000Z") });
processor.append({ value: 0, date: new Date("2022-08-19T08:05:25.000Z") });
processor.append({ value: 0, date: new Date("2022-08-19T08:06:25.000Z") });
processor.append({ value: 1, date: new Date("2022-08-19T08:07:25.000Z") });
console.log(processor.getOutputs());