根据日期 + 持续时间(分钟)对数组(甘特图时间表)进行排序 - 使用静态中断(日期 + 持续时间)

Sort array(gantt schedule) based on date + duration(min) - with static breaks(date+duration)

我有一个基于甘特图的数组。该数组包含具有以下属性的对象

{
    id: string;
    startTime: Date;
    durationEstimated: number;
    isBreak: boolean;
}

和一些通用值。基于这些值,我需要遍历数组并根据先前的值 sort/update startTime 。在这样做的同时,我还需要考虑 "isBreak"(静态值 – startTime/durationEstimated 永远不会改变)

例如,假设我有这个数组:

[ 
    {id: '1', startTime: "2020-04-01T08:30:00", durationEstimated: 60, isBreak: false},
    {id: '2', startTime: "2020-04-01T09:00:00", durationEstimated: 15, isBreak: true},
    {id: '3', startTime: "2020-04-01T09:45:00", durationEstimated: 60, isBreak: false},
    {id: '4', startTime: "2020-04-01T10:45:00", durationEstimated: 60, isBreak: false},
    {id: '5', startTime: "2020-04-01T11:45:00", durationEstimated: 60, isBreak: false},
    {id: '6', startTime: "2020-04-01T12:00:00", durationEstimated: 60, isBreak: true},
    {id: '7', startTime: "2020-04-01T13:45:00", durationEstimated: 60, isBreak: false}
] 

第一个 item(id='1'),将 运行 持续 30 分钟。然后 break(id='2') 15 分钟,然后在开始下一个 item(id='3')[= 之前​​完成最后 30 分钟49=]。 (新项目永远不会添加到位置 0)

假设我需要向其中添加另一个对象(开始时间无关紧要)

{id: '8', startTime: "2022-05-01T14:30:00", durationEstimated: 60, isBreak: false} 

我将其推入位置 1 的数组,然后数组将如下所示:

[ 
    {id: '1', startTime: "2020-04-01T09:30:00", durationEstimated: 60, isBreak: false}, 
    {id: '8', startTime: "2022-05-01T14:30:00", durationEstimated: 60, isBreak: false} 
    {id: '2', startTime: "2020-04-01T09:00:00", durationEstimated: 15, isBreak: true}, 
    {id: '3', startTime: "2020-04-01T09:45:00", durationEstimated: 60, isBreak: false}, 
    {id: '4', startTime: "2020-04-01T10:45:00", durationEstimated: 60, isBreak: false},
    {id: '5', startTime: "2020-04-01T11:45:00", durationEstimated: 60, isBreak: false},
    {id: '6', startTime: "2020-04-01T12:00:00", durationEstimated: 60, isBreak: true},
    {id: '7', startTime: "2020-04-01T13:45:00", durationEstimated: 60, isBreak: false}
] 

这是我要开始排序和更新第一个元素之后所有元素的开始时间的地方。因此,它应该将项目移动到合适的休息时间。

预期结果:

[ 
    {id: '1', startTime: "2020-04-01T08:30:00", durationEstimated: 60, isBreak: false}, 
    {id: '2', startTime: "2020-04-01T09:00:00", durationEstimated: 15, isBreak: true}, 
    {id: '8', startTime: "2020-04-01T09:45:00", durationEstimated: 60, isBreak: false},
    {id: '3', startTime: "2020-04-01T10:45:00", durationEstimated: 60, isBreak: false}, 
    {id: '4', startTime: "2020-04-01T11:45:00", durationEstimated: 60, isBreak: false},
    {id: '6', startTime: "2020-04-01T12:00:00", durationEstimated: 60, isBreak: true},
    {id: '5', startTime: "2020-04-01T13:45:00", durationEstimated: 60, isBreak: false},
    {id: '7', startTime: "2020-04-01T14:45:00", durationEstimated: 60, isBreak: false}
] 

真实数组长约 60-80 行,包含多个中断 + 不同的持续时间估计值。

尝试过

当我不得不在数组中四处移动项目以解决中断时间时,我总是会遇到问题。

我的想法是遍历数组检查每个项目,将其与前一个项目进行比较(startTime+duration)并将新日期添加到当前迭代项目开始时间。然后通过每个项目执行此操作。问题是当中断发生时,因为它们是静态的并且从不更新。

如果您只将新项目添加到数组的最后一个位置,我就可以正常工作(因为我不需要排序,只能检查以前的值)。但在实际应用中,会在任意位置添加新项

不确定如何将其转换为 JavaScript,但我认为我有一个用 Python 编写的解决方案似乎有效。

import datetime, json

data = [ 
    {'id': '1', 'startTime': "2020-04-01T08:30:00", 'durationEstimated': 60, 'isBreak': False},
    {'id': '2', 'startTime': "2020-04-01T09:00:00", 'durationEstimated': 15, 'isBreak': True},
    {'id': '3', 'startTime': "2020-04-01T09:45:00", 'durationEstimated': 60, 'isBreak': False},
    {'id': '4', 'startTime': "2020-04-01T10:45:00", 'durationEstimated': 60, 'isBreak': False},
    {'id': '5', 'startTime': "2020-04-01T11:45:00", 'durationEstimated': 60, 'isBreak': False},
    {'id': '6', 'startTime': "2020-04-01T12:00:00", 'durationEstimated': 60, 'isBreak': True},
    {'id': '7', 'startTime': "2020-04-01T13:45:00", 'durationEstimated': 60, 'isBreak': False}
]

new_data = []

original_data_in_dict_form = {}
breaks = {}
sort_dict = {}
for item in data:
    start_date_obj = datetime.datetime.strptime(item['startTime'], "%Y-%m-%dT%H:%M:%S")

    if item['isBreak']:
        breaks[item['id']] = item
        breaks[item['id']]['endTime'] = start_date_obj + datetime.timedelta(minutes=item['durationEstimated'])
    else:
        original_data_in_dict_form[item['id']] = item
        original_data_in_dict_form[item['id']]['endTime'] = start_date_obj + datetime.timedelta(minutes=item['durationEstimated'])

for break_id in breaks:
    for original_id in original_data_in_dict_form:
        if breaks[break_id]['startTime'] > original_data_in_dict_form[original_id]['startTime'] and breaks[break_id]['endTime'] < original_data_in_dict_form[original_id]['endTime']:
            original_data_in_dict_form[original_id]['endTime'] += datetime.timedelta(minutes=breaks[break_id]['durationEstimated'])
        if original_id not in sort_dict:
            sort_dict[original_id] = original_data_in_dict_form[original_id]['endTime']

for original_id, end_time in sorted(sort_dict.items(), key=lambda p: p[1], reverse=False):
    new_data.append(original_data_in_dict_form[original_id])

print(new_data)

endTime 排序,这显然可以转换为其他内容。这很可能是非常低效的,但应该可以让你继续。

我设法在 Torxed 答案的帮助下让它工作。

首先我遍历每个项目并设置一个结束时间

items = items.map(item => {
    item.startTime = new Date(item.startTime);
    const endTime = new Date(item.startTime);
    endTime.setMinutes(endTime.getMinutes() + item.durationEstimated);
    item.endTime = endTime;
    return item;
});

接下来我将 real*" 和 **break 项目过滤到数组中

const realItems = items.filter(x => !x.break);
const breakItems = items.filter(x => x.break);

Loop through all realItems

Set the startTime from previous values endTime

Get item startTime + duration = endTime

realItems.forEach((realItem, index) => {
    if (index !== 0) {
        realItem.startTime = new Date(realItems[index - 1].endTime);
        const endTime = new Date(new Date(realItem.startTime));
        endTime.setMinutes(endTime.getMinutes() + realItem.durationEstimated);
        realItem.endTime = endTime;
    } else {
        realItem.startTime = new Date(realItem.startTime);
        const endTime = new Date(new Date(realItem.startTime));
        endTime.setMinutes(endTime.getMinutes() + realItem.durationEstimated);
        realItem.endTime = endTime;
    }
});

接下来我循环遍历 breakItems 并检查项目的结束时间是否 >= 休息的开始时间。在那种情况下,我会在第一个响应之后遍历所有项目,并将中断的持续时间添加到项目的两个 startTime/endTime 中。

for (const breakItem of breakItems) {
    const breakStart = new Date(breakItem.startTime).getTime();
    for (let x = 0; x < realItems.length; x++) {
        const realItem = realItems[x];
        const realEnd = new Date(realItem.endTime).getTime();

        if (realEnd >= breakStart + realItem.durationEstimated * 60000) {
            const items = realItems.slice(x, realItems.length);
            for (const item of items) {
                item.startTime = new Date(item.startTime);
                item.startTime.setMinutes(item.startTime.getMinutes() + breakItem.durationEstimated);
                item.startTime = item.startTime;
                item.endTime = new Date(item.endTime);
                item.endTime.setMinutes(item.endTime.getMinutes() + breakItem.durationEstimated);
                item.endTime = item.endTime;
            }
            break;
        }
    }
}