Javascript - 向前移动重叠间隔
Javascript - Move forward overlapping intervals
有这样的输入:
[
{key: 'a', start: 0, end: 100}, // 100ms of duration
{key: 'b', start: 10, end: 30}, // 20ms of duration
{key: 'c', start: 110, end: 200}, // 90ms of duration,
{key: 'd', start: 300, end: 400},
]
我想要这个输出:
{key: 'a', start: 0, end: 100}, // 100ms of duration
{key: 'b', start: 100, end: 120}, // still 20ms of duration
{key: 'c', start: 120, end: 210}, // still 90ms of duration
{key: 'd', start: 300, end: 400}, // no modifications
我只需要修复重叠的间隔
获取项目的持续时间(通过从其 end
属性 中减去其 start
属性),设置其 start
属性 到最后一项的 end
属性 并将其 end
属性 设置为持续时间加上其 start
属性.
const arr=[{key:"a",start:0,end:100},{key:"b",start:10,end:30},{key:"c",start:110,end:200},{key:"d",start:300,end:400}];
for (let i = 1; i < arr.length; i++) {
if (arr[i].start < arr[i - 1].end) {
const duration = arr[i].end - arr[i].start;
arr[i].start = arr[i - 1].end;
arr[i].end = arr[i].start + duration;
}
}
console.log(arr)
假设您的输出是一个对象数组,您可以使用 Array.reduce()
.
const input = [
{ key: 'a', start: 0, end: 100 }, // 100ms of duration
{ key: 'b', start: 10, end: 30 }, // 20ms of duration
{ key: 'c', start: 110, end: 200 }, // 90ms of duration
{ key: 'd', start: 300, end: 400 },
];
const output = input.reduce(
/**
* @param outArray {Array<{ key: string, start: number, end: number }>} The accumulated array output by .reduce()
* @param key {string} The key of the current item
* @param start {number} The start time of the current item
* @param end {number} The end time of the current item
* @param idx {number} The current item's index
*/
(outArray, { key, start, end }, idx) => {
// nextStart =
// if we're on the first item, use 0
// if start is greater than the end time, just use start
// else the end time of the previous item
const nextStart = Math.max(start, outArray[idx - 1]?.end ?? 0);
// add the new item to the output
outArray.push({
key,
start: nextStart,
// add the previous end (aka, the current start) and the duration of the item
end: nextStart + end - start,
});
// return our output array
return outArray;
},
[] // initialize our output array as the empty array
);
console.log(output);
如果您想使用经验丰富的 JS 程序员可能使用的可读性较差的 hax0r 语法,您可以使用一行 reduce()
回调来实现。
const input = [
{ key: 'a', start: 0, end: 100 }, // 100ms of duration
{ key: 'b', start: 10, end: 30 }, // 20ms of duration
{ key: 'c', start: 110, end: 200 }, // 90ms of duration
];
const output = input.reduce(
// can be one line, but expanded for readability
(outArray, { key, start, end }, idx) => [
...outArray,
{
key,
start: Math.max(start, outArray[idx - 1]?.end ?? 0),
end: Math.max(start, outArray[idx - 1]?.end ?? 0) + end - start
}
],
[]
);
console.log(output);
第一种方法 运行s 稍微 对于长输入数组(我测试了 1200 个条目)更快,因为第二种方法在每次迭代时创建一个新数组并重新计算outArray[idx - 1]?.end ?? 0
。这段代码在我用了 4 年的机器上 运行 大约需要 16 秒。
const input = new Array(300).fill(0).flatMap((_, i) => {
const keyBase = i * 4;
i *= 400;
return [
{ key: (keyBase).toString(36), start: i + 0, end: i + 100 }, // 100ms of duration
{ key: (keyBase + 1).toString(36), start: i + 10, end: i + 30 }, // 20ms of duration
{ key: (keyBase + 2).toString(36), start: i + 110, end: i + 200 }, // 90ms of duration
{ key: (keyBase + 3).toString(36), start: i + 300, end: i + 400 },
];
});
const method1 = () => input.reduce(
(outArray, { key, start, end }, idx) => {
const nextStart = Math.max(start, outArray[idx - 1]?.end ?? 0);
outArray.push({
key,
start: nextStart,
end: nextStart + end - start,
});
return outArray;
},
[]
);
const method2 = () => input.reduce(
(outArray, { key, start, end }, idx) => [
...outArray,
{
key,
start: Math.max(start, outArray[idx - 1]?.end ?? 0),
end: Math.max(start, outArray[idx - 1]?.end ?? 0) + end - start
}
],
[]
);
const sum = (acc, x) => acc + x;
const avg = arr => arr.reduce(sum, 0) / arr.length;
const methods = ['Method1', 'Method2'];
const obs = new PerformanceObserver(items =>
['Method1', 'Method2'].forEach(m =>
console.log(m, avg(items.getEntriesByName(m).map(e => e.duration)))
));
obs.observe({ type: 'measure', buffered: true });
for (let i = 0; i < 20000; i++) {
methods.forEach((m, i) => {
performance.mark(i);
i === 0 ? method1() : method2();
i === 0 ? performance.measure(m, i) : performance.measure(m, 0, i);
});
}
setTimeout(() => obs.disconnect(), 0);
有这样的输入:
[
{key: 'a', start: 0, end: 100}, // 100ms of duration
{key: 'b', start: 10, end: 30}, // 20ms of duration
{key: 'c', start: 110, end: 200}, // 90ms of duration,
{key: 'd', start: 300, end: 400},
]
我想要这个输出:
{key: 'a', start: 0, end: 100}, // 100ms of duration
{key: 'b', start: 100, end: 120}, // still 20ms of duration
{key: 'c', start: 120, end: 210}, // still 90ms of duration
{key: 'd', start: 300, end: 400}, // no modifications
我只需要修复重叠的间隔
获取项目的持续时间(通过从其 end
属性 中减去其 start
属性),设置其 start
属性 到最后一项的 end
属性 并将其 end
属性 设置为持续时间加上其 start
属性.
const arr=[{key:"a",start:0,end:100},{key:"b",start:10,end:30},{key:"c",start:110,end:200},{key:"d",start:300,end:400}];
for (let i = 1; i < arr.length; i++) {
if (arr[i].start < arr[i - 1].end) {
const duration = arr[i].end - arr[i].start;
arr[i].start = arr[i - 1].end;
arr[i].end = arr[i].start + duration;
}
}
console.log(arr)
假设您的输出是一个对象数组,您可以使用 Array.reduce()
.
const input = [
{ key: 'a', start: 0, end: 100 }, // 100ms of duration
{ key: 'b', start: 10, end: 30 }, // 20ms of duration
{ key: 'c', start: 110, end: 200 }, // 90ms of duration
{ key: 'd', start: 300, end: 400 },
];
const output = input.reduce(
/**
* @param outArray {Array<{ key: string, start: number, end: number }>} The accumulated array output by .reduce()
* @param key {string} The key of the current item
* @param start {number} The start time of the current item
* @param end {number} The end time of the current item
* @param idx {number} The current item's index
*/
(outArray, { key, start, end }, idx) => {
// nextStart =
// if we're on the first item, use 0
// if start is greater than the end time, just use start
// else the end time of the previous item
const nextStart = Math.max(start, outArray[idx - 1]?.end ?? 0);
// add the new item to the output
outArray.push({
key,
start: nextStart,
// add the previous end (aka, the current start) and the duration of the item
end: nextStart + end - start,
});
// return our output array
return outArray;
},
[] // initialize our output array as the empty array
);
console.log(output);
如果您想使用经验丰富的 JS 程序员可能使用的可读性较差的 hax0r 语法,您可以使用一行 reduce()
回调来实现。
const input = [
{ key: 'a', start: 0, end: 100 }, // 100ms of duration
{ key: 'b', start: 10, end: 30 }, // 20ms of duration
{ key: 'c', start: 110, end: 200 }, // 90ms of duration
];
const output = input.reduce(
// can be one line, but expanded for readability
(outArray, { key, start, end }, idx) => [
...outArray,
{
key,
start: Math.max(start, outArray[idx - 1]?.end ?? 0),
end: Math.max(start, outArray[idx - 1]?.end ?? 0) + end - start
}
],
[]
);
console.log(output);
第一种方法 运行s 稍微 对于长输入数组(我测试了 1200 个条目)更快,因为第二种方法在每次迭代时创建一个新数组并重新计算outArray[idx - 1]?.end ?? 0
。这段代码在我用了 4 年的机器上 运行 大约需要 16 秒。
const input = new Array(300).fill(0).flatMap((_, i) => {
const keyBase = i * 4;
i *= 400;
return [
{ key: (keyBase).toString(36), start: i + 0, end: i + 100 }, // 100ms of duration
{ key: (keyBase + 1).toString(36), start: i + 10, end: i + 30 }, // 20ms of duration
{ key: (keyBase + 2).toString(36), start: i + 110, end: i + 200 }, // 90ms of duration
{ key: (keyBase + 3).toString(36), start: i + 300, end: i + 400 },
];
});
const method1 = () => input.reduce(
(outArray, { key, start, end }, idx) => {
const nextStart = Math.max(start, outArray[idx - 1]?.end ?? 0);
outArray.push({
key,
start: nextStart,
end: nextStart + end - start,
});
return outArray;
},
[]
);
const method2 = () => input.reduce(
(outArray, { key, start, end }, idx) => [
...outArray,
{
key,
start: Math.max(start, outArray[idx - 1]?.end ?? 0),
end: Math.max(start, outArray[idx - 1]?.end ?? 0) + end - start
}
],
[]
);
const sum = (acc, x) => acc + x;
const avg = arr => arr.reduce(sum, 0) / arr.length;
const methods = ['Method1', 'Method2'];
const obs = new PerformanceObserver(items =>
['Method1', 'Method2'].forEach(m =>
console.log(m, avg(items.getEntriesByName(m).map(e => e.duration)))
));
obs.observe({ type: 'measure', buffered: true });
for (let i = 0; i < 20000; i++) {
methods.forEach((m, i) => {
performance.mark(i);
i === 0 ? method1() : method2();
i === 0 ? performance.measure(m, i) : performance.measure(m, 0, i);
});
}
setTimeout(() => obs.disconnect(), 0);