检测范围在Google日历样式事件列表中重叠

时间:2015-02-15 20:17:57

标签: javascript arrays algorithm for-loop range

我需要帮助修复现有代码以完成我想要做的事情。

,包含以下示例数据:

var SAMPLE_DATA = [{start: 30, end: 150}, {start: 540, end: 600}, {start: 560, end: 620}, {start: 610, end: 670}];

我需要执行以下操作:

  • 遍历每个样本对象
  • 确定当前对象范围(obj.start:obj.end)是否与任何其他对象范围重叠。
  • 将该对象的重叠总数记录到totalSlots属性
  • 确定"索引"对象(用于它的从左到右定位)

我想要完成的模型:

mockup of final results

正如您在模型中看到的那样,slotIndex用于确定显示的从左到右的顺序。 totalSlots是它共享空间的对象数(1表示它是唯一的对象)。 100 / totalSlots告诉我广场的宽度(即totalSlots=2,表示它是100/2,或50%的容器宽度)。

我的代码的当前输出

Obj[0] slotIndex=0, totalSlots=0
Obj[1] slotIndex=1, totalSlots=1
Obj[2] slotIndex=1, totalSlots=2
Obj[3] slotIndex=0, totalSlots=1 

我的代码的预期/期望输出:

Obj[0] slotIndex=0, totalSlots=0
Obj[1] slotIndex=0, totalSlots=1
Obj[2] slotIndex=1, totalSlots=2
Obj[3] slotIndex=0, totalSlots=1 

代码:

detectSlots: function(oldEventArr) {
  oldEventArr.sort(this.eventSorter);
  var newEventArr = [],
    n = oldEventArr.length;

  for (var i = 0; i < n; i++) {
    var currObj = oldEventArr[i];
    if ('undefined' == typeof currObj.totalSlots) {
      currObj.slotIndex = 0;
      currObj.totalSlots = 0;
    }
    for (var x = 0; x < n; x++) {
      if (i == x) { 
        continue;
      }
      var nextObj = oldEventArr[x];
      if (currObj.start <= nextObj.end && nextObj.start <= currObj.end) {
        currObj.totalSlots++;
        nextObj.slotIndex++;

      }
    }
    newEventArr.push(currObj);
  }
  return newEventArr;
}

请帮我弄清楚我的代码出了什么问题。我大约90%的人确定问题出在if(currObj.start <= nextObj.end && nextObj.start <= currObj.end)语句中,我指定/递增了值,但我可以使用额外的一组眼睛。

2 个答案:

答案 0 :(得分:0)

像这样

var not_overlap = (currObj.end <= nextObj.start || nextObj.end <= currObj.start);
if (!not_overlap) { ...

var overlap = (currObj.end > nextObj.start && nextObj.end < currObj.start);
if (overlap) { ...

答案 1 :(得分:0)

可以使用图着色算法计算slotIndex值。请注意,强力算法在时间上是指数级的,并且只是一小组重叠时隙的可行解决方案。其他算法是启发式算法,您不会保证可能的最小插槽。

以下是您的问题的启发式示例:

...
// init
  var newEventArr = [], n = oldEventArr.length;

  for (var i = 0; i < n; i+=1) {
    var currObj = oldEventArr[i];
    newEventArr.push({"start":currObj.start,"end":currObj.end,"slotIndex":undefined,"totalSlots":0});
  }

  var link = {};

  // create link lists and totals
  for (var i = 0; i < n; i+=1) {
    var currObj = newEventArr[i];
    if (!link.hasOwnProperty(""+i))
      link[""+i] = {};

    for (var j = i+1; j < n; j+=1) {
      var nextObj = newEventArr[j];
      var not_overlap = (currObj.end <= nextObj.start || nextObj.end <= currObj.start);
      if (!not_overlap) {        
        currObj.totalSlots+=1;
        nextObj.totalSlots+=1;

        link[""+i][""+j] = 1;
        if (!link.hasOwnProperty(""+j))
          link[""+j] = {};
        link[""+j][""+i] = 1;
      }
    }
  }

  var arrities = [];
  for (var i = 0; i < n; i+=1) {
    arrities.push( {"arrity":newEventArr[i].totalSlots, "indx":i} );
  }

  // sort by arrities [a better solution is using a priority queue]
  for (var i = 0; i < n-1; i+=1) {
    var current_arrity = -1, indx = -1;
    for (var j = i; j < n; j+=1) {
      if (arrities[j].arrity > current_arrity) {
        indx = j;
        current_arrity = arrities[j].arrity;
      }
    }
    var temp = arrities[i];
    arrities[i] = arrities[indx];
    arrities[indx] = temp;
  }

  for (var i = 0; i < n; i+=1) {
    var nodeIndex = arrities[i].indx;
    // init used colors
    var colors = [];
    for (var j = 0; j < n; j+=1) {
      colors.push(0);
    }
    //find used colors on links
    for (var k in link[""+nodeIndex]) {
      var color = newEventArr[k].slotIndex;
      if (color || color === 0)
        colors[color] += 1;
    }
    //find the first unused color
    for (var j = 0; j < n; j+=1) {
      if (colors[j] <= 0) {
        // color the node
        newEventArr[nodeIndex].slotIndex = j;
        break;
      }
    }
  }
  return newEventArr;
...