从数组

时间:2018-04-12 17:17:54

标签: javascript arrays algorithm logic

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

我有一个这样的数组:

    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进行比较,并尝试将差异扣除到此数组中。

2 个答案:

答案 0 :(得分:2)

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

// 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)

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

答案 1 :(得分:1)

非常棒的挑战。

我将在时间跨度之间进行迭代,并确定将其视为重复的时间。为此我想到了下一个可能的案例。

  1. timeA在timeB内启动,timeA在timeB结束后结束
  2. timeA在timeB内开始,timeA在timeB结束之前结束
  3. timeA结束timeB和timeA在timeB启动之前开始
  4. timeA在timeB结束后结束
  5. 我希望这就是你要找的东西:)

    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);