我目前正在分析我的 sleep 数据(在 d3
的帮助下),并且我的 sleep 跟踪应用程序有一系列时间/日期,代表 sleep 周期的开始和结束时间。
[
{
"startDate": "2017-12-25 00:09:00 +0100",
"endDate": "2017-12-25 00:50:00 +0100"
},
{
"startDate": "2017-12-25 01:45:00 +0100",
"endDate": "2017-12-25 02:11:00 +0100"
},
{
"startDate": "2017-12-25 02:26:00 +0100",
"endDate": "2017-12-25 12:37:00 +0100"
},
...
]
根据这些条目,我想创建一个直方图类型的图表,显示我在一天中的给定小时和分钟内 sleep 的可能性有多大。因此,沿 X 轴将有 1,440 个刻度,代表一天中的每一分钟,条形的高度将表示我在该给定分钟休眠的可能性(使用简单的计数)。
目前,我正在创建一个包含所有间隔之间的所有单独分钟的数组(即,在上面的第一个条目中,将有 41 个对象代表 00:09 到 00:50 之间的每一分钟),然后匹配它们一天总共 1,440 分钟。当它们匹配时,将“一天中的一分钟”的计数加一。
因此,随着时间的推移,我可以看到我可能会在 01:00 sleep ,并在 12:30 醒来。
我有大约 3,100 个 sleep 条目,虽然我当前的代码似乎可以工作,但需要很长时间才能浏览我的条目(可以理解,因为 map 中还有 map )。如果我尝试在 Codesandbox 中仅对 1,000 个条目运行它,则大约一分钟后我不会得到结果。
而且,它……感觉效率低下。我确信一定有一种更有效的方法来做到这一点(我想知道是否有一个 d3 函数可以使它更容易,但我找不到)。
我遇到的部分问题是知道要搜索什么 - 是直方图吗?频率图?还有别的吗?
import * as d3 from 'd3';
import { add, format, getHours, getMinutes } from 'date-fns';
import { flatMap, map } from 'lodash';
// For each interval in the source data, create an array of the minutes
// in that interval
// e.g. For an interval time 00:10:00 to 00:18:00,
// return 9 dates (00:10:00, 00:11:00, 00:12:00, etc.)
const minutesFromIntervals = flatMap(data, (interval) =>
d3.timeMinute.range(
new Date(interval.startDate),
new Date(interval.endDate),
),
);
// Create an array of all the minutes in a day between midnight and
// midnight (1440 minutes)
const minutesOfDay = d3.timeMinute.range(
new Date(2020, 0, 1),
add(new Date(2020, 0, 1), { hours: 24 }),
);
// Map over the minutes of a day and see which interval minutes match
const results = map(minutesOfDay, (o) => {
let count = 0;
const outerDate = new Date(o);
const hour = getHours(outerDate);
const minute = getMinutes(outerDate);
map(minutesFromIntervals, (p) => {
const innerDate = new Date(p);
if (getHours(innerDate) === hour && getMinutes(innerDate) === minute) {
count += 1;
}
});
return {
key: format(o, 'HH:mm'),
value: count,
};
});
console.log({ results });
// results (example):
// [
// { key: "00:00", value: 0 },
// { key: "00:01", value: 1 },
// { key: "00:02", value: 1 },
// { key: "00:03", value: 1 },
// { key: "00:04", value: 2 },
// { key: "00:05", value: 2 },
// { key: "00:06", value: 1 },
// { key: "00:07", value: 3 },
// ...
// ]
最佳答案
恐怕您无法对 O(n^2)
复杂度做太多事情,但只需消除 就可以大大降低每个步骤的成本日期
方面,而是从整数 Angular 看待它。
当您处理时间时,您总是会遇到一个问题,即您还需要包含一些日期。然后还有闰年、时区和夏令时。相反,如果你看一下它,比如 1440 分钟,第 i 分钟表示午夜后的第 i 分钟,你就不必再处理时间了。
在这里,我将偏移量计算为自您休眠当天午夜以来的分钟数,然后计算您的 sleep 持续时间(以分钟为单位)。如果你在12点之前 sleep 并在12点之后醒来,我会使用%1440
重新从午夜开始计数。
一直以来,我不是解析和计算 O(n^2)
日期,而是为每个条目只进行 5 次日期计算,因此 O(n)
。现在您可以将其绘制为条形图,每第 60 个值上有一个刻度,刻度格式如 d + ":00"
或 d + "h"
这使它看起来像一个时间戳。
const differenceInMinutes = dateFns.differenceInMinutes;
const parse = dateFns.parse;
const startOfDay = dateFns.startOfDay;
const data = [{
"startDate": "2017-12-24 23:49:00 +0100",
"endDate": "2017-12-25 00:03:00 +0100"
},
{
"startDate": "2017-12-25 00:09:00 +0100",
"endDate": "2017-12-25 00:50:00 +0100"
},
{
"startDate": "2017-12-25 01:45:00 +0100",
"endDate": "2017-12-25 02:11:00 +0100"
},
{
"startDate": "2017-12-25 02:26:00 +0100",
"endDate": "2017-12-25 12:37:00 +0100"
},
].map(d => ({
startDate: parse(d.startDate),
endDate: parse(d.endDate),
}));
// This is the result, with minute `x` denoting `x` minutes after midnight
const total = 1440;
const result = new Array(total).fill(0);
data.forEach(d => {
const offset = differenceInMinutes(d.startDate, startOfDay(d.startDate));
const duration = differenceInMinutes(d.endDate, d.startDate);
for (let i = 0; i < duration; i++) {
result[(i + offset) % total] += 1;
}
});
for (let i = 0; i < total; i += 60) {
console.log(i / 60, " ", result.slice(i, i + 60).join(" "));
}
<script src="https://pagecdn.io/lib/date-fns/123/date_fns.js"></script>
关于javascript - 给定一个日期间隔范围,创建一个包含一天中所有 1440 分钟的数组,其中包含源间隔中每分钟出现的频率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64519645/