对可能没有直接重叠的多个重叠时间块进行分组

时间:2016-09-07 11:44:14

标签: javascript arrays

我正在尝试通过重叠对时间段进行分组,但我无法弄清楚如何完成它。

我有一个非常简单的数组,形式为[{start_at: Date, end_at: Date, etc.etc. }]

我把它们放在我看来像这样

<---slot1----><----slot5----><--slot6-->
  <--slot2-><--slot4--->            <--slot7-->
    <----slot3---->

找到直接重叠的插槽并不难,我只是将一个插槽与下一个插槽与(StartA <= EndB) and (EndA >= StartB)进行比较 from here

现在我想将重叠的插槽(插槽1,2,3,4和5)分组,但不包括插槽6和7,并将这两个放在他们自己的组中。像[[Slot (has 1 through 5)][Slot (has 6 and 7)]]

这样的东西

我现在很想解决这个问题,我希望这里有人可以帮助我。

2 个答案:

答案 0 :(得分:1)

我建议创建一个Slot对象,其中包含:

  • 广告位中的array项,
  • 这些项目的最早start_at日期,
  • 这些项目的最新end_at

通过保持最新的广告位范围,您不必将新项目与每个广告位的项目进行比较。您只需要与插槽本身进行比较。

现在,您必须按start_at对商品进行排序。然后,您可以通过以下方式减少数组:

  • 为第一个项目
  • 创建Slot
  • 设置Slot&#39; s start_atend_at以模仿第一项
  • 转到第二项,检查与第一项Slot的重叠
    • 如果重叠,
      • 将第二项推送到Slot项目数组,然后
      • start_at设置为Slot.start_atitem2.start_at
      • 的最低要求
      • end_at
      • 执行相同(最多)
    • 如果不重叠,
      • 为第二项创建新的Slot,重复此Slotitem3(等等)

示例实现(我建议您根据个人喜好重写它。我没有做任何整洁的类/原型/等等,也没有彻底测试它)

&#13;
&#13;
function createSlot(initialItem) {
 var slot = {
   items: [initialItem],
   start: initialItem.start,
   end: initialItem.end
 };
  
  slot.addItem = function(item) {
    slot.items.push(item);
    slot.start = Math.min(slot.start, item.start);
    slot.end = Math.max(slot.end, item.end);
  }
  
  return slot;
};
  
function itemsOverlap(item1, item2) {
  return item1.start <= item2.end &&
    item1.end >= item2.start;
};

var slots = [];
var items = randomItems(10);


items.slice(1).reduce(function(currentSlot, item) {
  if (itemsOverlap(currentSlot, item)) {
    currentSlot.addItem(item); 
    return currentSlot;
  }
  
  slots.push(currentSlot);
  return createSlot(item);
}, createSlot(items[0]));

console.log(
  slots.map(function(slot) { return slot.items.length; }));



// Create random data
function randomItems(n) {
  var arr = [];
  for (var i = 0; i < n; i += 1) {
   arr.push(generateRandomItem()); 
  }
  return arr.sort(function(a, b) { return a.start - b.start; });
};


function randomHourTimespan() {
  return Math.random() * 60 * 60 * 1000;
};

function randomHalfDayTimespan() {
  return randomHourTimespan() * 12;
};

function generateRandomItem() {
  var start = Date.now() + randomHalfDayTimespan();
  var end = start + randomHourTimespan();
  
  return { start: new Date(start), end: new Date(end) };
}
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我实施了一个简单的算法来对有关startend值的广告位进行分组。

这是一个工作小提琴https://jsfiddle.net/LeoAref/gg6q0mby/,您将找到该分组的视觉演示。

var timeSlots = [
  {start: 0, end: 3},
  {start: 1, end: 2},
  {start: 2, end: 4},
  {start: 4, end: 6},
  {start: 4, end: 8},
  {start: 5, end: 6}
];

timeSlots.forEach((slot, index) => {
  var slotElem = document.createElement('div');

  slotElem.classList.add('slot');
  slotElem.style.top = index * 25 + 'px';
  slotElem.style.left = slot.start * 30 + 'px';
  slotElem.style.width = (slot.end - slot.start) * 30 + 'px';

  document.body.appendChild(slotElem);
});

var groups = [];

timeSlots.forEach(slot => {
  added = false;

  if (groups.length) {
    var index = 0;

    do {
      group = groups[index];

        if (slot.start >= group.start && slot.start < group.end ||
          slot.end <= group.end && slot.end > group.start
      ) {
        group.slots.push(slot);

        group.start = Math.min(slot.start, group.start);
        group.end = Math.max(slot.end, group.end);

        added = true;
      }
    } while (!added && ++index < groups.length);

    if (!added) {
        groups.push({start: slot.start, end: slot.end, slots: [slot]});
    }
  } else {
    groups.push({start: slot.start, end: slot.end, slots: [slot]});
  }
})

groups.forEach(group => {
  var groupElem = document.createElement('div');

  groupElem.classList.add('group');
  groupElem.style.left = group.start * 30 + 'px';
  groupElem.style.width = (group.end - group.start) * 30 - 2 + 'px';

  document.body.appendChild(groupElem);
})