Don't do duplicate work in getLastMensesStart

This commit is contained in:
Julia Friesel
2018-10-14 13:08:56 +02:00
parent d01721daed
commit 1aeaac8504
2 changed files with 49 additions and 64 deletions
+45 -62
View File
@@ -26,70 +26,49 @@ export default function config(opts) {
minCyclesForPrediction = opts.minCyclesForPrediction || 3
}
function getLastMensesStart(targetDateString) {
const targetDate = LocalDate.parse(targetDateString)
const withWrappedDates = bleedingDaysSortedByDate
.filter(day => !day.bleeding.exclude)
.map(day => {
day.wrappedDate = LocalDate.parse(day.date)
return day
})
function findLatestMensesStart(bleedingDays) {
if (!bleedingDays.length) return null
// the index of the first bleeding day before the target day
const index = withWrappedDates.findIndex(day => {
return (
day.wrappedDate.isEqual(targetDate) ||
day.wrappedDate.isBefore(targetDate)
)
})
if (index < 0) {
withWrappedDates.forEach(day => delete day.wrappedDate)
return null
}
const prevBleedingDays = withWrappedDates.slice(index)
const lastMensesStart = prevBleedingDays.find((day, i) => {
return noBleedingDayWithinThreshold(day, prevBleedingDays.slice(i + 1))
// assumes bleeding days are ordered latest first, and
// excluded values already removed
const lastMensesStart = bleedingDays.find((day, i) => {
return noBleedingDayWithinThreshold(day, bleedingDays.slice(i + 1))
})
function noBleedingDayWithinThreshold(day, previousBleedingDays) {
const periodThreshold = day.wrappedDate.minusDays(maxBreakInBleeding + 1)
return !previousBleedingDays.some(({ wrappedDate }) => {
return (
wrappedDate.equals(periodThreshold) ||
wrappedDate.isAfter(periodThreshold)
)
})
const localDate = LocalDate.parse(day.date)
const threshold = localDate.minusDays(maxBreakInBleeding + 1).toString()
return !previousBleedingDays.some(({ date }) => date >= threshold)
}
withWrappedDates.forEach(day => delete day.wrappedDate)
return lastMensesStart
}
function getFollowingMensesStart(targetDateString) {
const targetDate = LocalDate.parse(targetDateString)
const withWrappedDates = bleedingDaysSortedByDate
function getLastMensesStartForDay(targetDateString) {
// the index of the first bleeding day before the target day
const index = bleedingDaysSortedByDate.findIndex(day => {
return day.date <= targetDateString && !day.bleeding.exclude
})
if (index < 0) return null
const prevBleedingDays = bleedingDaysSortedByDate.slice(index)
return findLatestMensesStart(prevBleedingDays)
}
function getFollowingMensesStartForDay(targetDateString) {
const followingBleedingDays = bleedingDaysSortedByDate
.filter(day => !day.bleeding.exclude)
.map(day => {
day.wrappedDate = LocalDate.parse(day.date)
return day
})
const firstBleedingDayAfterTargetDay = withWrappedDates
.reverse()
.find(day => {
return day.wrappedDate.isAfter(targetDate)
})
withWrappedDates.forEach(day => delete day.wrappedDate)
const firstBleedingDayAfterTargetDay = followingBleedingDays
.find(day => day.date > targetDateString)
return firstBleedingDayAfterTargetDay
}
function getCycleDayNumber(targetDateString) {
const lastMensesStart = getLastMensesStart(targetDateString)
const lastMensesStart = getLastMensesStartForDay(targetDateString)
if (!lastMensesStart) return null
const targetDate = LocalDate.parse(targetDateString)
const lastMensesLocalDate = LocalDate.parse(lastMensesStart.date)
@@ -111,7 +90,7 @@ export default function config(opts) {
}
function getPreviousCycle(dateString) {
const startOfCycle = getLastMensesStart(dateString)
const startOfCycle = getLastMensesStartForDay(dateString)
if (!startOfCycle) return null
const dateBeforeStartOfCycle = LocalDate
.parse(startOfCycle.date)
@@ -123,10 +102,10 @@ export default function config(opts) {
function getCycleForDay(dayOrDate) {
const dateString = typeof dayOrDate === 'string' ? dayOrDate : dayOrDate.date
const cycleStart = getLastMensesStart(dateString)
const cycleStart = getLastMensesStartForDay(dateString)
if (!cycleStart) return null
const cycleStartIndex = cycleDaysSortedByDate.indexOf(cycleStart)
const nextMensesStart = getFollowingMensesStart(dateString)
const nextMensesStart = getFollowingMensesStartForDay(dateString)
if (nextMensesStart) {
return cycleDaysSortedByDate.slice(
cycleDaysSortedByDate.indexOf(nextMensesStart) + 1,
@@ -137,16 +116,20 @@ export default function config(opts) {
}
}
function getAllMensesStarts(day, collectedDates) {
day = day || LocalDate.now().toString()
collectedDates = collectedDates || []
const lastStart = getLastMensesStart(day)
if (!lastStart) {
return collectedDates
} else {
const newDay = LocalDate.parse(lastStart.date).minusDays(1).toString()
collectedDates.push(lastStart.date)
return getAllMensesStarts(newDay, collectedDates)
function getAllMensesStarts(initialBleedingDays = bleedingDaysSortedByDate) {
return recurse(initialBleedingDays.filter(d => !d.bleeding.exclude))
function recurse(bleedingDays, collectedDates) {
collectedDates = collectedDates || []
const lastStart = findLatestMensesStart(bleedingDays)
if (!lastStart) {
return collectedDates
} else {
collectedDates.push(lastStart.date)
const index = bleedingDays.indexOf(lastStart)
const remainingDays = bleedingDays.slice(index + 1)
return recurse(remainingDays, collectedDates)
}
}
}
@@ -189,8 +172,8 @@ export default function config(opts) {
lastStart = lastStart.plusDays(periodDistance)
const nextPredictedDates = [lastStart.toString()]
for (let j = 0; j < periodStartVariation; j++) {
nextPredictedDates.push(lastStart.minusDays(j+1).toString())
nextPredictedDates.push(lastStart.plusDays(j+1).toString())
nextPredictedDates.push(lastStart.minusDays(j + 1).toString())
nextPredictedDates.push(lastStart.plusDays(j + 1).toString())
}
nextPredictedDates.sort()
predictedMenses.push(nextPredictedDates)