时间排序数据结构

时间:2012-03-08 10:36:34

标签: c# .net datetime data-structures

我有大量从数据库中检索的数据。它们按时间戳排序(每个项目都有),我希望能够快速滚动浏览这些数据,并能够在特定时间内检索下一个/上一个记录。

是否有任何数据结构可以帮助我这样做?目前,我通过数据进行二元搜索以检索下一个项目。

插入,删除和编辑很少见(但偶尔也有必要),因此寻找时间是最关键的。

有什么想法吗?

一个简单的例子:

public class TimedDataItem
{
    DateTime Timestamp { get; set; }
}

// Large populated timestamped data set    
IList<TimedDataItem> timedDataItemsList = new Last<TimedDataItem>();

// Get a 'random' time
DateTime myTime = DateTime.Now;

// Find items around that 'random' time
TimedDataItem next = timedDataItemsList.FirstOrDefault(t=>t.Timestamp > myTime);
TimedDataItem previous = timedDataItemsList.LastOrDefault(t=>t.Timestamp < myTime);

// Also foreach over the collection in time order if required
foreach (TimedDataItem item in timedDataItemsList)
    DoStuff(item);

// Inserts, deletions, edits are extremely rare

感谢。

1 个答案:

答案 0 :(得分:3)

编辑回答

首选解决方案 - SortedSet

plus:排序集合,允许逻辑使用某个范围内的元素

减:不确定搜索算法是什么,没有上一个和下一个

public class TimedDataItem   
{
    public DateTime Timestamp { get; set; }
}
class TimedDataItemComparer : IComparer<TimedDataItem>
{
    public int Compare(TimedDataItem x, TimedDataItem y)
    {
        return x.Timestamp.CompareTo(y.Timestamp);
    }
}
class Program
{
    static void Main(string[] args)
    {
        SortedSet<TimedDataItem> ss = 
            new SortedSet<TimedDataItem>(new TimedDataItemComparer());

        // example data
        ss.Add(new TimedDataItem() { Timestamp = DateTime.Now.AddDays(-5) });
        TimedDataItem min = new TimedDataItem() { Timestamp = DateTime.Now.AddDays(-3) };
        ss.Add(min);
        ss.Add(new TimedDataItem() { Timestamp = DateTime.Now.AddDays(-1) });
        ss.Add(new TimedDataItem() { Timestamp = DateTime.Now });
        ss.Add(new TimedDataItem() { Timestamp = DateTime.Now.AddDays(1) });
        TimedDataItem max = new TimedDataItem() { Timestamp = DateTime.Now.AddDays(3) };
        ss.Add(max);
        ss.Add(new TimedDataItem() { Timestamp = DateTime.Now.AddDays(5) });

        // get elements in range
        SortedSet<TimedDataItem> view = ss.GetViewBetween(min, max);

        foreach (TimedDataItem item in view)
        {
            Console.WriteLine(item.Timestamp);
        }
    }    
}

解决方案SortedList

plus: sorted,typeSafe,允许next和prev

减:线性搜索

 SortedList<TimedDataItem, TimedDataItem> sl =
            new SortedList<TimedDataItem, TimedDataItem>(new TimedDataItemComparer());

 TimedDataItem first = new TimedDataItem() { Timestamp = DateTime.Now.AddDays(-5) };
 TimedDataItem second = new TimedDataItem() { Timestamp = DateTime.Now.AddDays(-3) };
 TimedDataItem third = new TimedDataItem() { Timestamp = DateTime.Now.AddDays(-1) };
 TimedDataItem fourth = new TimedDataItem() { Timestamp = DateTime.Now };
 TimedDataItem fifth = new TimedDataItem() { Timestamp = DateTime.Now.AddDays(1) };
 TimedDataItem sixth = new TimedDataItem() { Timestamp = DateTime.Now.AddDays(3) };
 TimedDataItem seventh = new TimedDataItem() { Timestamp = DateTime.Now.AddDays(5) };

 sl.Add(first, first);
 sl.Add(second, second);
 sl.Add(third, third);
 sl.Add(fourth, fourth);
 sl.Add(fifth, fifth);
 sl.Add(sixth, sixth);
 sl.Add(seventh, seventh);

 // unfortunatelly according to MSDN: 
 //   This method uses a linear search; therefore, this method is 
 //   an O(n) operation, where n is Count.
 int index = sl.IndexOfKey(third);
 TimedDataItem prev = sl.ElementAt(index - 1).Value;
 TimedDataItem next = sl.ElementAt(index + 1).Value;

解决方案ArrayList

plus:允许使用索引binarySearch(!)

减:你应该怎样处理无序集合中的索引......

ArrayList al = new ArrayList();
al.Add(first);
al.Add(second);
al.Add(third);
al.Add(fourth);
al.Add(fifth);
al.Add(seventh);
al.Add(seventh);

int index2 = al.BinarySearch(third, new TimedDataItemComparer2());
// al[index2] does not make sense
// as there is no guarantee, that al[index2-1] is the element
// with previous DateTime ...

class TimedDataItemComparer2 : IComparer
{
    public int Compare(object x, object y)
    {
        if (x is TimedDataItem && y is TimedDataItem)
            return ((TimedDataItem)x).Timestamp.
                       CompareTo(((TimedDataItem)y).Timestamp);
        else
            return -1;
    }
}