Если возможно, я бы сохранял экземпляры в массиве, отсортированном по StartTime, а затем вызывал BinarySearch для определения индексов в массиве, в котором заканчиваются границы.
Затем, учитывая это, вы можете легко получить доступ к подмножеству на основе диапазона дат.
Я разработал общий класс, который также может помочь вам в этом:
public class BinarySearcher<T>
{
// Possibly passed to the call to BinarySort.
private class ComparisonComparer : Comparer<T>
{
Comparison<T> comparison;
internal static IComparer<T> Create(Comparison<T> comparison)
{
// If comparison is null, return the default comparer for T.
if (comparison == null)
{
// Return the default.
return Comparer<T>.Default;
}
// Return a new implementation.
return new ComparisonComparer(comparison);
}
private ComparisonComparer(Comparison<T> comparison)
{
this.comparison = comparison;
}
public override int Compare(T x, T y)
{
return comparison(x, y);
}
}
// The elements.
T[] elements;
// The IComparable implementation.
IComparer<T> comparer;
// Do not assume sorting.
public BinarySearcher(IEnumerable<T> elements) :
this(elements, false, (IComparer<T>) null) { }
// Use default comparer.
public BinarySearcher(IEnumerable<T> elements, bool sorted) :
this(elements, sorted, (IComparer<T>) null) { }
// Assume no sorting.
public BinarySearcher(IEnumerable<T> elements,
Comparison<T> comparer) :
this(elements, false,
ComparisonComparer.Create(comparer)) { }
// Convert to IComparable<T>.
public BinarySearcher(IEnumerable<T> elements, bool sorted,
Comparison<T> comparer) :
this(elements, sorted,
ComparisonComparer.Create(comparer)) { }
// No sorting.
public BinarySearcher(IEnumerable<T> elements,
IComparer<T> comparer) :
this(elements, false, comparer) { }
// Convert to array.
public BinarySearcher(IEnumerable<T> elements, bool sorted,
IComparer<T> comparer) :
this(elements.ToArray(), sorted, comparer) { }
// Assume no sorting.
public BinarySearcher(T[] elements) : this(elements, false) { }
// Pass null for default comparer.
public BinarySearcher(T[] elements, bool sorted) :
this(elements, sorted, (IComparer<T>) null) { }
// Assume not sorted.
public BinarySearcher(T[] elements, Comparison<T> comparer) :
this(elements, false, ComparisonComparer.Create(comparer)) { }
// Create IComparable<T> from Comparable<T>.
public BinarySearcher(T[] elements, bool sorted,
Comparison<T> comparer) :
this(elements, sorted, ComparisonComparer.Create(comparer)) { }
// Assume the elements are not sorted.
public BinarySearcher(T[] elements, IComparer<T> comparer) :
this(elements, false, comparer) { }
public BinarySearcher(T[] elements, bool sorted,
IComparer<T> comparer)
{
// If the comparer is null, create the default one.
if (comparer == null)
{
// Set to the default one.
comparer = Comparer<T>.Default;
}
// Set the comparer.
this.comparer = comparer;
// Set the elements. If they are sorted already, don't bother,
// otherwise, sort.
if (!sorted)
{
// Sort.
Array.Sort(elements, this.comparer);
}
// Set the elements.
this.elements = elements;
}
public IEnumerable<T> Between(T from, T to)
{
// Find the index for the beginning.
int index = Array.BinarySearch(this.elements, from, comparer);
// Was the item found?
bool found = (index >= 0);
// If the item was not found, take the bitwise
// compliment to find out where it would be.
if (!found)
{
// Take the bitwise compliment.
index = ~index;
}
// If the item was found, cycle backwards from
// the index while there are elements that are the same.
if (found)
{
// Cycle backwards.
for (; index >= 0 &&
comparer.Compare(from, elements[index]) == 0;
--index) ;
// Add one to the index, since this is on the element
// that didn't match the comparison.
index++;
}
// Go forward now.
for ( ; index < elements.Length; index++)
{
// Return while the comparison is true.
if (comparer.Compare(elements[index], to) <= 0)
{
// Return the element.
yield return elements[index];
}
else
{
// Break
yield break;
}
}
}
}
Большинство из того, что здесь есть, являются помощниками для инициализации класса, которым потребуется метод сравнения двух элементов (IComparer<T>
и Comparable<T>
взяты здесь). Этот класс также позволяет вам использовать необработанный массив, который уже отсортирован, на случай, если вы захотите позже добавить / удалить / обновить элементы в нужных местах (без необходимости постоянно прибегать к массиву).
Мясо класса в призыве к Между. Он принимает значение from, которое будет передано статическому методу BinarySearch в классе Array, передавая реализацию IComparer, которую использует этот экземпляр (он принимает значения по умолчанию, если они не переданы).
Если значение не существует, оно выясняет, где оно будет , существовать в массиве, а затем циклически переключается назад, если в массиве несколько элементов с одинаковым значением.
Затем он циклически переходит вперед, возвращая элементы в перечислении, в то время как текущий элемент меньше или равен значению to.
В вашей конкретной ситуации, если у вас есть такой класс:
public class Task
{
public string Name;
public DateTime StartTime;
}
Вы можете сделать следующее:
// Create tasks.
Task[] tasks =
{
new Task() { Name = "Task 1", StartTime = new DateTime(2009, 02, 18) },
new Task() { Name = "Task 2", StartTime = new DateTime(2009, 02, 16) },
new Task() { Name = "Task 3", StartTime = new DateTime(2009, 02, 12) },
new Task() { Name = "Task 4", StartTime = new DateTime(2009, 02, 11) },
new Task() { Name = "Task 5", StartTime = new DateTime(2009, 02, 10) },
new Task() { Name = "Task 6", StartTime = new DateTime(2009, 02, 01) },
new Task() { Name = "Task 7", StartTime = new DateTime(2009, 02, 09) }
};
// Now create the indexer.
BinarySearcher<Task> searcher = new BinarySearcher<Task>(tasks,
(x, y) => Comparer<DateTime>.Default.Compare(x.StartTime, y.StartTime));
foreach (Task t in searcher.Between(
new Task() { StartTime = new DateTime(2009, 02, 13) },
new Task() { StartTime = new DateTime(2009, 02, 10) }))
{
// Write.
Console.WriteLine(t);
}