Код: Выделить всё
public class History : IEntityBase, IEntityDates
{
[Key]
public long Id { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
/* =================== Not Mapped properties =================== */
[NotMapped]
public bool HasGap { get; set; }
[NotMapped]
public bool IsGapSixMonthsOrMore { get; set; }
}
Вопрос: Что такое пробел?
A: Разрыв определяется как минимальное количество дней между двумя датами (не включая), чтобы свойство HasGap было истинным.
Здесь также приведена некоторая информация о типах истории, которые мы можем ожидать, и возможные результаты:
- История может иметь нулевую EndDate (A), и это означает, что история все еще продолжается, и каждая история, чья StartDate после A.StartDate не будет пробела.
- В отсортированном списке истории могут перекрываться. Это означает, что одна история может закончиться, в то время как другая история началась за 2 месяца до окончания.
- В истории будет пробел, если histories.StartDate предшествует histories[i-1]. EndDate не менее 7 (пропускных) дней.
- histories.IsGapSixMonthsOrMore — это истинная история.StartDate предшествует истории[i-1].EndDate не менее чем на 6 месяцев. .
- StartDate также может иметь значение null, но никогда не бывает так, потому что мы выполняем эту проверку в другой функции при получении всех данных.
Если придумаю что-нибудь еще, я напишу.
Мы написали два разных метода расчета, но оба они зависят от списка историй, которые нужно отсортировать. Итак, нам интересно, есть ли способ выполнить эту проверку без зависимости от сортируемого списка?
Его решение выполняет вычисления вдвое быстрее, чем мое.
Вот это его:
Код: Выделить всё
public static void CalculateGaps(this List dateRanges, int? gapThreshold)
{
if (dateRanges == null || dateRanges.Count < 2 || gapThreshold is null)
return;
// Sort the ranges by Start date
var sortedRanges = dateRanges.OrderBy(r => r.StartDate)
.ThenBy(r => r.EndDate)
.ToList();
// Initialize the first range with no gap (as it's the first in the list)
sortedRanges[0].HasGap = false;
sortedRanges[0].IsGapSixMonthsOrMore = false;
// Keep track of the latest 'end' date encountered
DateTime currentMaxEnd = sortedRanges[0].EndDate?.Date ?? DateTime.MaxValue;
for (int i = 1; i < sortedRanges.Count; i++)
{
// If there's a gap between the current maximum end and the next range's start
if (currentMaxEnd < sortedRanges[i].StartDate?.Date.AddDays(-gapThreshold.Value))
{
sortedRanges[i].HasGap = true; // Gap found
// Check if the gap is more than 6 months
sortedRanges[i].IsGapSixMonthsOrMore = sortedRanges[i].StartDate?.Date.AddMonths(-6) >= currentMaxEnd;
}
else
{
sortedRanges[i].HasGap = false;
sortedRanges[i].IsGapSixMonthsOrMore = false;
}
// Update the max end to be the later of the current max end or this range's end
var nextEnd = sortedRanges[i].EndDate?.Date ?? DateTime.MaxValue;
currentMaxEnd = currentMaxEnd > nextEnd ? currentMaxEnd : nextEnd;
}
}
Код: Выделить всё
public static void CalculateGapsV2(this List histories, int? gapThreshold)
{
if (histories.Count == 0)
return;
histories = histories.OrderBy(h => h.StartDate).ToList();
var queue = new Queue();
histories[0].HasGap = false; // First entry has no previous history to compare with
histories[0].IsGapSixMonthsOrMore = false; // First entry has no previous history to compare with
queue.Enqueue(histories[0].EndDate?.Date);
for (int i = 1; i < histories.Count; i++)
{
var previousEndDate = histories[i - 1].EndDate?.Date;
var currentStartDate = histories[i].StartDate?.Date;
while (queue.Count > 0)
{
if (queue.Peek() is null) //ongoing history
{
histories[i].HasGap = false;
histories[i].IsGapSixMonthsOrMore = false;
break;
}
else if (queue.Peek() > currentStartDate)
{
histories[i].HasGap = false;
histories[i].IsGapSixMonthsOrMore = false;
queue.Enqueue(histories[i].EndDate?.Date);
break;
}
else
{
queue.Dequeue();
}
}
if (queue.Count == 0)
{
if (currentStartDate is null)
{
histories[i].HasGap = false;
histories[i].IsGapSixMonthsOrMore = false;
}
else
{
var gapDays = (currentStartDate.Value - previousEndDate.Value).TotalDays;
//A gap is defined as total days between two employments
//So if a gapThreshold = 1
//Has gap would be false if hist[0].EndDate = 2024-10-1 and hist[1].StartDate = 2024-10-2
//But has gap would be true if hist[0].EndDate = 2024-10-1 and hist[1].StartDate = 2024-10-3
//Since we only have one full day between, and that is 2024-10-2
histories[i].HasGap = gapDays > gapThreshold;
// The six month gap is defined as six months or more
// hist[0].EndDate = 2024-1-15 and hist[1].StartDate = 2024-7-15
// This would make the bool true
// If startDate was 2024-07-14 -> IsGapSixMonthsOrMore would be false
histories[i].IsGapSixMonthsOrMore = currentStartDate.Value.AddMonths(-6) >= previousEndDate.Value;
queue.Enqueue(histories[i].EndDate?.Date);
}
}
}
}
Оба метода прошли все наши тестовые примеры.
Просто чтобы подтвердить вопрос. Есть ли более эффективный способ сделать это, не зависящий от списка историй, которые нужно отсортировать? Если нет, есть ли возможности для улучшения метода CalculateGaps()?
Подробнее здесь: https://stackoverflow.com/questions/790 ... of-objects