C# 中的 CircularBuffer IDictionary?

发布于 2024-08-01 17:12:23 字数 169 浏览 3 评论 0原文

我需要一个 CircularBuffer IDictionary。 谁能指出我一个好的开源实现。

因此,一个具有最大容量的 IDictionary,假设配置为 100 个项目,当添加第 101 个项目时,原始第一个项目将从字典中弹出/删除,从而确保项目计数永远不会超过 100。

谢谢

I need a CircularBuffer IDictionary. Can anyone point me to a good open source implementation.

So a IDictionary that has a maximum capacity, say configured to 100 items, which when item 101 is added the original first item is popped/removed from the dictionary thus ensuring the item count never exceeds 100.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

2024-08-08 17:12:23

不久前,我用 C# 3.0 编写了一个循环缓冲区的完整实现,并在 CodePlex 上发布了源代码。 它遵循 BCL 设计准则,并实现 System.Collections 中的所有适当接口。

我相信使用 Dictionary 作为支持集合而不是 List 应该很容易适应。

I wrote a complete implementation of a circular buffer in C# 3.0 not too long ago, and release the source on CodePlex. It follows BCL design guidelines, and implements all the appropiate interfaces from System.Collections.

I believe it should be very easy to adapt to use a Dictionary<TKey, TValue> as the backing collection instead of a List<T>.

烟─花易冷 2024-08-08 17:12:23

五分钟谷歌搜索后发现两个:

Found two after five minutes of googling:

苦行僧 2024-08-08 17:12:23

这个怎么样:

    public class CircularDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        private Queue<TKey> m_ItemInsertList = new Queue<TKey>();
        private int m_ItemsToHold = 100;

        public int ItemsToHold
        {
            get { return m_ItemsToHold; }
            set {
                if (value < 1)
                    throw new ArgumentException("Items to hold must be at least 1");
                m_ItemsToHold = value; 
            }
        }

        public new void Add(TKey key, TValue value)
        {
            base.Add(key, value);
            if (m_ItemInsertList.Count == m_ItemsToHold)
                base.Remove(m_ItemInsertList.Dequeue());
            m_ItemInsertList.Enqueue(key);
        }
    }

How about this:

    public class CircularDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        private Queue<TKey> m_ItemInsertList = new Queue<TKey>();
        private int m_ItemsToHold = 100;

        public int ItemsToHold
        {
            get { return m_ItemsToHold; }
            set {
                if (value < 1)
                    throw new ArgumentException("Items to hold must be at least 1");
                m_ItemsToHold = value; 
            }
        }

        public new void Add(TKey key, TValue value)
        {
            base.Add(key, value);
            if (m_ItemInsertList.Count == m_ItemsToHold)
                base.Remove(m_ItemInsertList.Dequeue());
            m_ItemInsertList.Enqueue(key);
        }
    }
凝望流年 2024-08-08 17:12:23

我不知道有任何这样的实现,但自己实现听起来并不难。 由于字典没有任何固有的顺序,因此字典中的键或值类型都需要有一些属性来表示它插入字典的顺序。 然后,在重写 Add 方法时,它可以检查计数是否达到最大值。 如果是,则查找现有的键值对,找到插入顺序属性最低的键值对,并将其替换为新的键值对。 否则,照常插入新的键值对。

I don't know of any such implementations, but it doesn't sound hard to implement yourself. Since dictionaries don't have any inherent order, either the key or the value type in the dictionary would need to have some property representing the order in which it was inserted into the dictionary. Then, in your override of the Add method, it could check to see if the count was at the max. If so, then look through the existing key-value pairs to find the one whose insert-order property is lowest and replace it with the new key-value pair. Otherwise, insert the new key-value pair as usual.

芯好空 2024-08-08 17:12:23

为了保持 O(1) 插入(删除超过 100 的最旧项目)和 O(1) 查找,您需要一个实现 IDictionary 的类保留内部有序列表。 如果更关心内存,那么像 SortedList 这样的 BST 实现可能更合适。 无论如何,您的类将包含 T[]Dictionary (或 SortedList)。 执行您自己的循环缓冲区索引(简单),并在添加、删除等方法中保持两个集合最新。 您将拥有:

  • O(1) 排队(向后)
  • O(n) 违反添加顺序的插入(因为您必须保持数组最新); 无论如何,你可能永远都不需要这个
  • O(1) 出队(从前面)
  • O(1) 或 O(log n) 键控查找

使其通用并实现 IDictionaryIDictionary 因为没有理由不这样做,并且您将获得性能优势。

一个主要考虑因素:如何处理重复的键? 我假设您实际上无法保留重复项,因此:

  • 抛出异常(如果从不存在重复键,那么插入两次内容只是一个错误)
  • 移至后面:检查 Count字典,然后使用 this[key] 索引器插入键。 如果大小增加,则检查列表是否已达到最大容量,从列表和字典中删除前面的项目,并将新项目添加到后面。 如果字典的大小没有增加,则将项目从列表中的现有位置移动到列表的后面。
  • 覆盖而不移动:与上一项相同,但不必弄乱列表。

最后,请注意内部列表保留键,而不是值。 这是为了确保超出列表容量时 O(1) 出队。

To keep O(1) insertion (with removal of the oldest item past 100) and O(1) lookups, you'll need a class that implements IDictionary and keeps an internal ordered list. If memory is more a concern, a BST implementation like SortedList could be more appropriate. Anyway, your class will contain both a T[] and a Dictionary<T,K> (or SortedList<T,K>). Do your own circular buffer indexing (easy), and keep both collections current in the add, remove, etc. methods. You'll have:

  • O(1) enqueue (to back)
  • O(n) insertion that violates order of adding (since you have to keep the array up to date); you'll likely never need this anyway
  • O(1) dequeue (from front)
  • O(1) or O(log n) keyed lookup

Make it generic and implement IDictionary<T,K> and IDictionary since there's no reason not to and you'll get an edge in performance.

One major consideration: what do you do about duplicate keys? I'm assuming you can't actually keep the duplicates, so:

  • Throw an exception (if there are never duplicate keys, so it's simply an error to insert something twice)
  • Move to back: check the Count of the dictionary, then insert the key using the this[key] indexer. if the size increases, then check if the list already has the maximum capacity, remove the front item from the list and dictionary and add the new item to the back. If the dictionary did not increase in size, move the item from its existing place in the list to the back of the list.
  • Overwrite without moving: The same as the previous item, but you don't have to mess with the list.

Finally, note that the internal list keeps keys, not values. This is to ensure O(1) dequeue when the list capacity is exceeded.

合久必婚 2024-08-08 17:12:23

我通过 System.Data.Sqlite (http://sqlite .phxsoftware.com/)包装器。 您可以将其存储在磁盘上或作为内存数据库。 您可以选择是否具有唯一键,并让数据库引擎为您处理索引。 您甚至可以为每个键设置多个值。

当您写入表时,请检查是否达到 100 条记录的限制,如果是,则在插入之前删除。 如果您想保留唯一键,SQLite 支持“插入或替换”命令。 也许这不像自定义 IDictionary 派生那么优雅,但它有效、灵活,并且很容易跨线程共享。

I've implemented something akin to this by using a SQLite database table via the System.Data.Sqlite (http://sqlite.phxsoftware.com/) wrapper. You can store it on disk or as an in-memory database. You can choose whether or not to have unique keys and let the database engine handle the indexing for you. You can even have multiple values per key.

As you write to the table, check to see if you're at the 100-record limit, and if so then delete before inserting. SQLite supports an "insert or replace" command if you want to preserve unique keys. Perhaps this isn't as elegant as a custom IDictionary derivation, but it works, it's flexible, and it's readily shared across threads.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文