检查是否已将用户分配到特定插槽

时间:2019-04-06 13:42:32

标签: javascript algorithm data-structures

我正在研究人员配置应用程序。我们具有将员工转移到团队的功能。我想添加验证来检查用户是否已经预订了该特定时间段。例如,在下面的屏幕截图中,用户 mate 位置重叠。不能在同一时间将他分配到两个团队。

enter image description here

这个问题更多地与数据结构有关。我编写的代码似乎可以正常工作,但我仍然不确定,我相信它可以做得更好。就像没有运行两个循环?。

如果需要修改数据结构以获得更好的性能,也可以。

https://codesandbox.io/s/pj2kmz1kox

class App extends Component {
  state = {
    selectedItem: {}
  };
  updateDate = (index, field, { target: { value } }) => {
    const { selectedItem } = this.state;
    const newSelectedItem = { ...selectedItem };
    newSelectedItem[index] = newSelectedItem[index] || {
      id: new Date().getTime()
    };
    newSelectedItem[index][field] = new Date(value);
    this.setState({
      selectedItem: newSelectedItem
    });
    this.valiateAvailibility();
  };

  handleDropdown = (index, { target: { value } }) => {
    const { selectedItem } = this.state;
    const newSelectedItem = { ...selectedItem };
    newSelectedItem[index] = newSelectedItem[index] || {
      id: new Date().getTime()
    };
    newSelectedItem[index]["userId"] = value;
    this.setState({
      selectedItem: newSelectedItem
    });
    this.valiateAvailibility();
  };

  valiateAvailibility = () => {
    const { selectedItem } = this.state;
    const error = {};
    for (let i in selectedItem) {
      const userId = selectedItem[i].userId;
      const id = selectedItem[i].id;
      const from = selectedItem[i].from;
      const to = selectedItem[i].to;
      for (let z in selectedItem) {
        const fromB = selectedItem[z].from;
        const toB = selectedItem[z].to;
        if (userId == selectedItem[z].userId && id !== selectedItem[z].id) {
          if (from <= toB && to >= fromB) {
            error[z] = "error";
          }
        }
      }
    }
    console.log("error", error);
  };

  render() {
    console.log(this.state.selectedItem);
    return (
      <div className="App">
        {[1, 2, 3].map((item, index) => {
          return (
            <div>
              <select onChange={e => this.handleDropdown(index, e)}>
                <option>Select User</option>
                <option value="12">Mate</option>
                <option value="23">Bill</option>
              </select>
              <input
                type="date"
                onChange={e => this.updateDate(index, "from", e)}
              />
              <input
                type="date"
                onChange={e => this.updateDate(index, "to", e)}
              />
            </div>
          );
        })}
      </div>
    );
  }
}

2 个答案:

答案 0 :(得分:1)

该演示包含class,其中包含一些使用ES6 Map存储日期范围的方法。每个说明都代表员工的时间表。 OP没有提及如何处理重叠的日期,因此这是日期范围验证规则:

  • 日期被转换为毫秒以进行比较(.getTime()

  • 如果一个开始日期大于另一个开始日期并且小于其结束日期,则使用最早的开始日期,然后新的结束日期将是两个结束日期中的较大者。

  • 如果输入开始日期大于输入结束日期,则会交换它们。

  • 每个范围都由一个索引存储。

顺便说一句,日期是准确的,但格式各不相同,我将把它留给OP。

class schedule {
  constructor(id) {
    this.id = id;
    this.index = 0;
    this.map = new Map;
  }
  addSlot([startString, endString]) {
    this.index = this.map.size;
    let startDate = new Date(startString);
    let endDate = new Date(endString);
    let startTime = startDate.getTime();
    let endTime = endDate.getTime()
    if (startTime > endTime) {
      let temp = endDate;
      endDate = startDate;
      startDate = temp;
    }
    if (this.map.size > 0) {
      for (let [key, value] of this.map) {
        let start = value[0].getTime();
        let end = value[1].getTime();
        let newStart = startTime > start && startTime < end ? value[0] : start > startTime && start < endTime ? startDate : false;
        let newEnd;
        if (newStart) {
          newEnd = end > endTime ? value[1] : endDate;
          this.map.set(key, [newStart, newEnd]);
        } else {
          this.map.set(this.index, [startDate, endDate]);
        }
      }
    } else {
      this.map.set(this.index, [startDate, endDate]);
    }
  }

  hasSlot(index) {
    return this.map.has(index);
  }

  getSlot(index) {
    return this.map.get(index);
  }

  viewSlots() {
    let list = '';
    for (let [key, value] of this.map) {
      list += `
      ${key}: [Start: ${value[0]} - 
          End: ${value[1]}]
      `;
    }
    return list;
  }

  removeSlot(index) {
    if (this.map.has(index)) {
      this.map.delete(index);
    } else {
      return index + 'does not exist';
    }
  }
}

const m = new schedule('Mate');

console.log(m.id);

m.addSlot(['04/19/2019', '04/28/2019']);
console.log(m.hasSlot(0));

m.addSlot(['04/21/2019', '05/12/2019']);
console.log(m.hasSlot(1));
console.log(m.getSlot(0));

m.addSlot(['08/19/2019', '09/12/2019']);
console.log(m.hasSlot(1));
console.log(m.getSlot(1));

console.log(m.viewSlots());

答案 1 :(得分:0)

如果您对更有效的数据结构感兴趣,可以尝试在此处使用二叉树。将您的非重叠间隔放入该树中。

由于您对非重叠间隔感兴趣,因此您在它们上定义了自然顺序:间隔A>如果间隔A在时间轴上位于间隔B的右侧,则间隔B。

您可以一次又一次地添加间隔,以确保每个新间隔都不与现有间隔重叠。对于每个新间隔,它将花费O(log n)。如果编辑了一个间隔,则必须删除相应的节点并添加一个新的节点,当然要保持二叉树的结构。

但是实际上,您可能只有很少的时间间隔,因此使用复杂的数据结构没有任何意义。您只需使用简单的间隔列表并对其进行迭代,就可以了。