JavaScript-计算连续工作日



例如,我有一个数组的计划如下:

[
{ _id: "1", project_id: "1", day: "2021-03-02" },
{ _id: "2", project_id: "1", day: "2021-03-01" },
{ _id: "3", project_id: "1", day: "2021-03-03" },
{ _id: "4", project_id: "2", day: "2021-03-01" },
{ _id: "5", project_id: "1", day: "2021-03-04" },
{ _id: "6", project_id: "1", day: "2021-03-10" }
]

我需要计算具有相同项目id的计划的连续天数(没有周末(。例如,结果需要是:

[
{ _id: "1", project_id: "1", day: "2021-03-02", count: 4 },
{ _id: "2", project_id: "1", day: "2021-03-01", count: 4 },
{ _id: "3", project_id: "1", day: "2021-03-03", count: 4 },
{ _id: "4", project_id: "2", day: "2021-03-01", count: 1 },
{ _id: "5", project_id: "1", day: "2021-03-04", count: 4 },
{ _id: "6", project_id: "1", day: "2021-03-10", count: 1 }
]

我尝试了以下方法,但它在同一项目的每个计划中都返回相同的计数:

let plans = [
{ _id: "1", project_id: "1", day: "2021-03-02" },
{ _id: "2", project_id: "1", day: "2021-03-01" },
{ _id: "3", project_id: "1", day: "2021-03-03" },
{ _id: "4", project_id: "2", day: "2021-03-01" },
{ _id: "5", project_id: "1", day: "2021-03-04" },
{ _id: "6", project_id: "1", day: "2021-03-10" }
];
plans.filter(p => new Date(p.day).getDay() !== 6 && new Date(p.day).getDay() !== 0).map((plan, i, arr) => {
let count = 1;
arr
.filter(p2 => plan.project_id === p2.project_id)
.sort((a, b) => new Date(a.day).getTime() - new Date(b.day).getTime())
.map((plan3, k, arr3) => {
if (k > 0) {
let tmpDate = new Date(arr3[k - 1].day);
if (tmpDate.getDay() === 5) {
tmpDate.setDate(tmpDate.getDate() + 3);
} else {
tmpDate.setDate(tmpDate.getDate() + 1);
}
if (tmpDate.getTime() === new Date(plan3.day).getTime()) {
count++;
}
}
});
plan.count = count;
})

console.log(plans);

问题是,当出现缺口时,不会创建新的系列。你用这个测试条件:

if (tmpDate.getTime() === new Date(plan3.day).getTime()) {
count++;
}

但你并不是说一个间隔后的计划不属于同一系列。。。你只是没有把它计算在内。但这一数字仍将适用于该计划。你真的应该像对待项目的切换一样对待一个缺口。

同样令人遗憾的是,对于属于同一项目的所有日子,您必须重做相同的分析。每次的结果都是一样的,所以这是效率的损失。这可以用一个循环来完成,而不需要嵌套循环。

以下是如何做到这一点。诚然,嵌套循环(具有.slice....forEach(,但这只是在数据的不同切片上。如果将所有这些迭代计算在一起,那么对于该内部循环,您总共完成了n次迭代。所以这并不意味着它是二次的。每个计划只有一次是内部循环的主题。

function nextWorkingDay(a) {
a = new Date(a); // clone
let d = a.getDay();
a.setDate(a.getDate() + (d < 5 ? 1 : 8 - d));
return a;
}
function addCounts(data) {
let sorted = [...data].sort((a,b) => 
a.project_id.localeCompare(b.project_id) || a.day.localeCompare(b.day)
);
let count = 0;
sorted.forEach((o, i, arr) => {
count++;
if (i === arr.length - 1 || arr[i+1].project_id != o.project_id 
|| +nextWorkingDay(o.day) !== Date.parse(arr[i+1].day)) {
// Note how a break in consecutive days is treated in the same
//   way as a break in the project_id
arr.slice(i - count + 1, i + 1).forEach(o => o.count = count);
count = 0;
}
});
}
// Sample data
let data = [
{ _id: "1", project_id: "1", day: "2021-03-02" },
{ _id: "2", project_id: "1", day: "2021-03-01" },
{ _id: "3", project_id: "1", day: "2021-03-03" },
{ _id: "4", project_id: "2", day: "2021-03-01" },
{ _id: "5", project_id: "1", day: "2021-03-04" },
{ _id: "6", project_id: "1", day: "2021-03-10" }
];
addCounts(data);
console.log(data);

最新更新