【问题标题】:Javascript - Move forward overlapping intervalsJavascript - 向前移动重叠间隔
【发布时间】:2021-12-23 04:16:13
【问题描述】:

有这个输入:

[
 {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

我只需要修复重叠的间隔

【问题讨论】:

    标签: javascript range intervals overlap


    【解决方案1】:

    获取项目的持续时间(通过从其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)

    【讨论】:

      【解决方案2】:

      假设你的输出是一个对象数组,你可以使用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);

      对于长输入数组(我测试了 1200 个条目),第一种方法运行速度稍微快,因为第二种方法在每次迭代时都会创建一个新数组并重新计算 outArray[idx - 1]?.end ?? 0。这个 sn-p 在我 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);

      【讨论】:

        猜你喜欢
        • 2015-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-07
        • 1970-01-01
        相关资源
        最近更新 更多