【问题标题】:Calculate unique time from time intervals in array根据数组中的时间间隔计算唯一时间
【发布时间】:2018-04-12 17:17:53
【问题描述】:

我有一种情况,我需要计算用户播放视频的唯一秒数。我得到一个数组playbackArray,在其中我得到用户开始播放视频的位置(beginPosition)和用户停止播放视频的位置(endPosition)。

我有一个这样的数组:

    let playbackArray = [
        {
            beginPosition: 0,
            endPosition: 30, // endPosition - beginPosition = 30
            blockNum: 0
        },
        {
            beginPosition: 45,
            endPosition: 65, // endPosition - beginPosition = 20
            blockNum: 1
        },
        {
            beginPosition: 55,
            endPosition: 85, // endPosition - beginPosition = 30
// but only 20 new seconds (65s - 85s) so total video playback is 30 + 20 + 20 = 70s.
            blockNum: 2
        }
    ]

基本上,如果数组中的块中有重叠时间,我 必须删除那些重叠的时间间隔并只计算 此数组中的唯一时间。

我看到的一种方法是以某种方式在这个数组上运行一个循环并遍历每个块并将当前块的 beginPosition 与前一个块的 endPosition 和

  1. 如果没有重叠,则将此差异添加到另一个数组中。
  2. 如果有重叠,则将当前块的 beginPosition 与之前所有块的 beginPosition 进行比较,并尝试将差值扣除到此数组中。

【问题讨论】:

  • 到目前为止你有什么尝试?
  • 又该如何选择生成的blockNums?
  • @ScottSauyet,blockNums 可以任意选择。
  • 暴力破解方法是使用所有观看秒数的集合。没有逻辑,保证独一无二。 :)
  • @HollyLeaves:我想你误解了这个问题。

标签: javascript arrays algorithm logic


【解决方案1】:

如果间隔首先按开始时间排序,那么我们可以根据三种情况将测试间隔 (-<-->-) 添加到不断增长的间隔列表 (-[--]-) 中:

// 1: Ignore current interval
      ----[--<--->--]----
      ----[---------]---- 

// 2: Merge top and current
      ----[--<---]-->----
      ----[---------]---- 

// 3: Add current to stack
      ----[---]---<-->---
      ----[---]---[--]---

这里有一个实现。样本数据涵盖了所有这些情况,并且没有开始排序。如果您的数据始终按间隔开始排序,您可以删除 sort 行(以及上面的 slice 调用):

// Example: ['a', 'b', 'c', 'd'] //=> 'd'
const last = stack => stack[stack.length - 1] 
// Example: ['a', 'b', 'c', 'd'] //=> ['a', 'b', 'c']
const init = stack => stack.slice(0, stack.length - 1) 
const start = interval => interval.beginPosition
const end = interval => interval.endPosition

const consolidateOverlaps = (intervals) => 
    intervals.slice(0) // don't mutate original array
    .sort((a, b) => start(a) < start(b) ? -1 : start(a) > start(b) ? 1 : 0)
    .reduce((stack, curr) => start(curr) < end(last(stack))
      ? end(curr) < end(last(stack)) 
        ? stack // Case 1
        : init(stack).concat(Object.assign(last(stack), {endPosition: end(curr)})) // Case 2
      : stack.concat(curr) // Case 3
    , [{endPosition: -Infinity}]) // base case to start reduction
    .slice(1) // remove that (now unnecessary) base case

const playbackArray = [
  {beginPosition: 0, endPosition: 30, blockNum: 0},
  {beginPosition: 45, endPosition: 65, blockNum: 1},
  {beginPosition: 55, endPosition: 85, blockNum: 2},
  {beginPosition: 90, endPosition: 110, blockNum: 3},
  {beginPosition: 95, endPosition: 100, blockNum: 4},
  {beginPosition: 20, endPosition: 40, blockNum: 5},
  {beginPosition: 130, endPosition: 200, blockNum: 6},
  {beginPosition: 140, endPosition: 250, blockNum: 7},
  {beginPosition: 150, endPosition: 225, blockNum: 8},
]

console.log(consolidateOverlaps(playbackArray))

请注意,生成的 blockNums 现在相当随意。将此结果转换为总秒数应该很容易:

consolidateOverlaps(playbackArray)
  .map(interval => interval.endPosition - interval.beginPosition)
  .reduce((a, b) => a + b, 0)

(如果您不需要间隔列表,这两行可以折叠到原始函数中。)

【讨论】:

    【解决方案2】:

    很棒的挑战。

    我将在时间跨度之间进行迭代,并确定它被视为重复的时间。为此,我考虑了下一个可能的情况。

    1. timeA 在 timeB 内开始,timeA 在 timeB 结束后结束
    2. timeA 在 timeB 内开始并且 timeA 在 timeB 结束之前结束
    3. timeA 在 timeB 内结束并且 timeA 在 timeB 开始之前开始
    4. timeA 在 timeB 结束后结束

    我希望这就是你要找的:)

    let playbackArray = [{
        beginPosition: 0,
        endPosition: 30, // endPosition - beginPosition = 30
        blockNum: 0
      },
      {
        beginPosition: 45,
        endPosition: 65, // endPosition - beginPosition = 20
        blockNum: 1
      },
      {
        beginPosition: 55,
        endPosition: 85, // endPosition - beginPosition = 30
        // but only 20 new seconds (65s - 85s) so total video playback is 30 + 20 + 20 = 70s.
        blockNum: 2
      }
    ]
    
    let repeat=0;
    let time = 0;
    
    
    for(var i =0; i<playbackArray.length; i++){
      time += playbackArray[i].endPosition - playbackArray[i].beginPosition;
    
      for(var j=i+1; j<playbackArray.length; j++){
        if(playbackArray[i].beginPosition > playbackArray[i+1].beginPosition ) {
        //play i starts inside play  j
          if(playbackArray[i].endPosition < playbackArray[i+1].endPosition ) {
            //All play i is inside play j
            repeat += playbackArray[i].endPosition - playbackArray[i].beginPosition;
          } else {
            //Play i ends after play j
            repeat += playbackArray[j].endPosition - playbackArray[i].beginPosition;
          }
        } 
        if(playbackArray[i].endPosition > playbackArray[j].beginPosition ) {
          //play i ends after play j started
           if(playbackArray[i].endPosition > playbackArray[j].endPosition ) {
           //play i ends after play j ended
           repeat += playbackArray[j].endPosition - playbackArray[i].beginPosition; 
          } else {
            //play i ends inside play j
            repeat += playbackArray[i].endPosition - playbackArray[j].beginPosition; 
          }
        }
      }
    }
    
    console.log("Total time:"+time,"Repeated time:"+repeat);
    var res = time-repeat;
    console.log("Real time:"+res);

    【讨论】:

    • 感谢您的回答。这是一个更简单且很好的答案,但这个答案的唯一问题是它在 beginPosition 和 endPosition 没有排序(按顺序)的情况下失败。
    猜你喜欢
    • 2017-03-25
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-18
    • 2021-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多