2013-05-01 66 views
0

我有一个应用程序接收某些“事件”,由12个字符串和一个DateTime唯一标识。在每个事件都关联一个字符串的结果。 我需要将这些事件保存在内存中(例如最多8小时),并且如果我再次收到同一事件,能够知道我已经收到它(在过去的8小时内)。 要存储的事件将小于1000. 我不能使用外部存储器,它必须在内存中完成。带日期时间+字符串键的目录,并自动删除旧条目

我的想法是使用一个字典,其中的键是一个由字符串和日期时间组成的类,该值是结果。

编辑:字符串本身(实际上是MAC地址)不能唯一标识事件,它是MAC和DateTime,这两个组合是唯一的,这就是为什么密钥必须由两者组成。 应用程序是一个从客户端接收特定事件的服务器:该事件在客户端由客户端MAC和客户端日期时间标记(不能使用guid)。 可能发生客户端重新传输相同的数据,并通过检查MAC /日期时间密钥的字典,我会知道我已经收到该数据。

然后,每隔一小时(例如),我可以对整个集合进行foreach并删除datetime超过8小时的所有关键字。

你可以提出一个更好的方法来解决问题或我选择的数据格式吗?在代码的性能和清洁方面。 或者更好的方式来删除旧数据,例如LINQ。

谢谢, 马蒂亚

+1

你的意思解释?目录听起来像*会使用外部存储。 – 2013-05-01 16:18:21

+0

哦,上帝,谢谢...是字典当然... – 2013-05-01 16:36:30

+0

为什么字符串和日期时间是unqiue?那么在你的收藏中,这个字符串可以多次出现? – 2013-05-01 16:55:40

回答

0

我会去一个字典。

这样你可以非常快速地搜索字符串(O(1)-operation)。

其他藏品慢:

  • OrderedDictionary:是缓慢的,因为它需要装箱和拆箱。
  • SortedDictionary:执行O(log n)操作。
  • 所有正常的数组和列表:使用O(n/2)操作。

一个例子:

public class Event 
{ 
    public Event(string macAddress, DateTime time, string data) 
    { 
     MacAddress = macAddress; 
     Time = time; 
     Data = data; 
    } 

    public string MacAddress { get; set; } 
    public DateTime Time { get; set; } 
    public string Data { get; set; } 
} 

public class EventCollection 
{ 
    private readonly Dictionary<Tuple<string, DateTime>, Event> _Events = new Dictionary<Tuple<string, DateTime>, Event>(); 

    public void Add(Event e) 
    { 
     _Events.Add(new Tuple<string, DateTime>(e.MacAddress, e.Time), e); 
    } 

    public IList<Event> GetOldEvents(bool autoRemove) 
    { 
     DateTime old = DateTime.Now - TimeSpan.FromHours(8); 
     List<Event> results = new List<Event>(); 
     foreach(Event e in _Events.Values) 
      if (e.Time < old) 
       results.Add(e); 

     // Clean up 
     if (autoRemove) 
      foreach(Event e in results) 
       _Events.Remove(new Tuple<string, DateTime>(e.MacAddress, e.Time)); 

     return results; 
    } 
} 
+0

有趣,但在每个事件都有一个值,我必须存储在字典中(我有三个元素:字符串(MAC),日期时间,字符串(事件的值))。 此外,与您的词典,我该如何清理词典并删除所有8小时以前的日期时间? – 2013-05-01 17:22:26

+0

我用一个例子更新了我的答案。 – 2013-05-01 17:25:30

+0

非常感谢这个书面例子,但正如我在之前的评论中所说的,我必须处理我的词典中的3个元素: string(MAC),datetime和另一个字符串,它是事件的值。 所以我的活动可以有“AABBCCDDEEFF”,2013-05-01T12:13:15,“活动的价值”。 有了您的解决方案,我可以在哪里存储“事件的价值”? 谢谢 – 2013-05-01 17:47:27

0

其中键是12人物造型标识符和所述结果和日期时间是该值的一部分,我会用一个OrderedDictionary。可悲OrderedDictionary是不通用的(键和值是对象),所以你需要做自己的铸造和类型检查。当您需要删除旧事件时,您可以通过OrderedDictionary进行foreach,并在您达到足够新的时间时停止。这假设您使用的日期时间是将它们添加到字典中。

+0

我编辑了这个问题,也许我还不清楚为什么日期时间必须在关键。 并且不,事件的日期不一定会按顺序排列。 – 2013-05-01 16:49:02

+0

啊,好的。如果日期时间不符合规定,我不会使用OrderedDicationary。就像达克斯说的那样,这种方法需要在每次插入后重新排序,如果只有1000个左右事件,则不会节省那么多时间。 – Cemafor 2013-05-01 16:57:48

1

活动时间必须到而不是成为关键的一部分 - 如果是,您如何能够告诉您已经收到此活动?所以你应该移动到一个字典,其中的键是事件名称,值是日期和结果的元组。

在一段时间后,你可以从字典中很容易与LINQ修剪旧数据:

dictionary = dictionary 
    .Where(p => p.Value.DateOfEvent >= DateTime.Now.AddHours(-8)) 
    .ToDictionary(); 
+0

我编辑了这个问题,也许我还不清楚为什么datetime必须在关键字中。 – 2013-05-01 16:53:21

+0

非常好的解决方案来删除旧数据,但如果我选择字典<元组<字符串,DateTime>,事件>解决方案来存储数据,是否有可能调整您的解决方案来检查Tuple键中的DateTime p.Value.DateOfEvent的? – 2013-05-01 18:33:12

+0

@MattiaDurli:当然 - 't => t.Item2.DateOfEvent> = ...',或者您决定保留日期的任何项目号。 – Jon 2013-05-01 21:33:52

1

如果要求规定,每小时更新一次就足够好,你永远有超过1000个项目字典,你的解决方案应该是完全足够的,并且可能是任何其他人看到你的代码最容易理解的。我可能会推荐不可变的结构来代替类,但就是这样。

如果有一个好处,立即删除它们而不是每小时一次,你可以做一些事情,你还可以添加一个计时器,正好是8小时后删除它,但你已经得到了处理线程安全清理所有计时器等。可能不值得。

我会避免OrderedDictionary方法,因为它更多的代码,并且可能会更慢,因为它必须重新排序每个插入。

这些日子里常见的口头禅主要关注保持代码简单,只在必要时进行优化。直到你有一个已知的瓶颈并对它进行了描述,你永远不知道你是否在优化正确的事情。 (从你的描述来看,没有分辨出哪部分是最慢的)。

+0

OrderedDictionary方法只会在插入时更慢(相对)删除旧事件时速度要快得多;)。但我同意,如果事件不合适,不值得。 – Cemafor 2013-05-01 16:59:43