开发者

First-in-first-out collection with maximum size and no duplication?

开发者 https://www.devze.com 2023-04-05 19:10 出处:网络
.NET seems to have a lot of data structure and collection types. Does it have a first-in-first-out collection with a maximum size and no duplication, or something similar to that?

.NET seems to have a lot of data structure and collection types. Does it have a first-in-first-out collection with a maximum size and no duplication, or something similar to that?

An example usage would be like for storing 5 most recently opened files. If a 6th object is added, dequeue the least recent object to kee开发者_如何学运维p the size to 5


You'll have to create a QueueSet that implements ICollection<T>. It can be a wrapper class that contains a collection as a backing store. It can be implemented as follows:

class QueueSet<T> : ICollection<T> 
{
    List<T> queue=new List<T>();
    int maximumSize;

    public QueueSet(int maximumSize){
        if(maximumSize<0)
            throw new ArgumentOutOfRangeException("maximumSize");
        this.maximumSize=maximumSize;
    }

    public T Dequeue(){
        if(queue.Count>0){
            T value=queue[0];
            queue.RemoveAt(0);
            return value;
        }
        return default(T);
    }

    public T Peek(){
        if(queue.Count>0){
            return queue[0];
        }
        return default(T);
    }

    public void Enqueue(T item){
        if(queue.Contains(item)){
            queue.Remove(item);
        }
        queue.Add(item);
        while(queue.Count>maximumSize){
            Dequeue();
        }
    }

    public int Count {
        get {
            return queue.Count;
        }
    }

    public bool IsReadOnly {
        get {
            return false;
        }
    }

    public void Add(T item)
    {
        Enqueue(item);
    }

    public void Clear()
    {
        queue.Clear();
    }

    public bool Contains(T item)
    {
        return queue.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        foreach(T value in queue){
            if(arrayIndex>=array.Length)break;
            if(arrayIndex>=0){
                array[arrayIndex]=value;
            }
            arrayIndex++;
        }
    }

    public bool Remove(T item)
    {
        if(Object.Equals(item,Peek())){
           Dequeue();
           return true;
        } else {
            return false;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return queue.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return queue.GetEnumerator();
    }
}

I release this code into the public domain.


You want a queue, no?

It doesn't really support maximum size and no duplication but you could inherit from Queue and add those features.

You could do so by overriding the Enqueue method. Something like this might work (but throw more appropriate exception types!):

    public class LimitedQueue : Queue
    {
        public override void Enqueue(object obj)
        {
            if (this.Count > 5)
                throw new Exception();

            if(this.Contains(obj))
                throw new Exception();
            base.Enqueue(obj);
        }
    }

A containing or wrapper or HAS-A class might look like this:

public class QueueWrapper<T>
{
     private Queue<T> _queue;
     public void Enqueue(T item)
     {
         if (_queue.Count > 5)
             throw new Exception();

         if(this.Contains(item))
             throw new Exception();

         _queue.Enqueue(item);
     }

     //Any other methods you might want to use would also need to be exposed similarly
}


have a look at this: Limit size of Queue<T> in .NET?

you basically need a Queue, if you manage to limit its size and get it "indexed" or "unique" then you are ok :)

I believe a bit of logic around a Dictionary would also work, what is the data type you will store? Strings?


This is what you want, HashQueue<T>, the hashed queued set.

Added some thread locks, protects from accidental locks. Keep in mind, that all HashSet operation breaks the order of existing queue.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Security.Permissions;

namespace ConsoleApplication
{
    internal class Program
    {
        [Serializable]
        private class HashQueue<T> : ISerializable, IDeserializationCallback, ISet<T>, ICollection<T>, IEnumerable<T>, IEnumerable
        {
            private int _maxCount;
            private Queue<T> _queue = new Queue<T>();
            private HashSet<T> _set = new HashSet<T>();

            public HashQueue(int maxCount = 0)
            {
                if (maxCount < 0) throw new ArgumentOutOfRangeException("maxCount");
                _maxCount = maxCount;
            }

            public bool Add(T item)
            {
                lock (this)
                {
                    if (_queue.Count == _maxCount)
                    {
                        _set.Remove(_queue.Dequeue());
                    }
                    if (_set.Add(item))
                    {
                        _queue.Enqueue(item);
                        return true;
                    }
                    return false;
                }
            }

            public bool Remove(T item)
            {
                lock (this)
                {
                    if (object.ReferenceEquals(_queue.Peek(), item))
                    {
                        return _set.Remove(_queue.Dequeue());
                    }
                    return false;
                }
            }

            public void Clear()
            {
                lock (this)
                {
                    _set.Clear();
                    _queue.Clear();
                }
            }

            public bool Contains(T item)
            {
                lock (this)
                {
                    return _set.Contains(item);
                }
            }

            public void CopyTo(T[] array, int arrayIndex)
            {
                lock (this)
                {
                    _queue.CopyTo(array, arrayIndex);
                }
            }

            public int Count
            {
                get
                {
                    lock (this)
                    {
                        return _queue.Count;
                    }
                }
            }

            public bool IsReadOnly
            {
                get
                {
                    return false;
                }
            }

            public void ProcessItems(Action<T> action)
            {
                lock (this)
                {
                    foreach (T item in _queue)
                    {
                        action(item);
                    }
                }
            }

            void ICollection<T>.Add(T item)
            {
                lock (this)
                {
                    if (_queue.Count == _maxCount)
                    {
                        _set.Remove(_queue.Dequeue());
                    }
                    if (!_set.Add(item))
                    {
                        throw new ArgumentOutOfRangeException("item");
                    }
                    _queue.Enqueue(item);
                }
            }

            public IEnumerator<T> GetEnumerator()
            {
                lock (this)
                {
                    return _queue.GetEnumerator();
                }
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                lock (this)
                {
                    return (IEnumerator)GetEnumerator();
                }
            }

            public void OnDeserialization(object sender)
            {
                lock (this)
                {
                    _set.OnDeserialization(sender);
                }
            }

            private void RebuildQuery()
            {
                _queue.Clear();
                foreach (T item in _set)
                {
                    _queue.Enqueue(item);
                }
            }

            public void ExceptWith(IEnumerable<T> other)
            {
                lock (this)
                {
                    _set.ExceptWith(other);
                    RebuildQuery();
                }
            }

            public void IntersectWith(IEnumerable<T> other)
            {
                lock (this)
                {
                    _set.IntersectWith(other);
                    RebuildQuery();
                }
            }

            public bool IsProperSubsetOf(IEnumerable<T> other)
            {
                lock (this)
                {
                    return _set.IsProperSubsetOf(other);
                }
            }

            public bool IsProperSupersetOf(IEnumerable<T> other)
            {
                lock (this)
                {
                    return _set.IsProperSupersetOf(other);
                }
            }

            public bool IsSubsetOf(IEnumerable<T> other)
            {
                lock (this)
                {
                    return _set.IsSubsetOf(other);
                }
            }

            public bool IsSupersetOf(IEnumerable<T> other)
            {
                lock (this)
                {
                    return _set.IsSupersetOf(other);
                }
            }

            public bool Overlaps(IEnumerable<T> other)
            {
                lock (this)
                {
                    return _set.Overlaps(other);
                }
            }

            public bool SetEquals(IEnumerable<T> other)
            {
                lock (this)
                {
                    return _set.SetEquals(other);
                }
            }

            public void SymmetricExceptWith(IEnumerable<T> other)
            {
                lock (this)
                {
                    _set.SymmetricExceptWith(other);
                    RebuildQuery();
                }
            }

            public void UnionWith(IEnumerable<T> other)
            {
                lock (this)
                {
                    _set.UnionWith(other);
                    RebuildQuery();
                }
            }

            [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
            void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
            {
                _set.GetObjectData(info, context);
            }
        }

        private static void Main(string[] args)
        {
            HashQueue<int> queue = new HashQueue<int>(5);
            queue.Add(1);
            queue.Add(2);
            queue.Add(3);
            queue.Add(4);
            queue.Add(5);
            queue.Add(6);
            queue.ProcessItems((i) => Console.Write(i));
            //foreach (int i in queue)
            //{
            //    Console.Write("{0}", i);
            //}
        }
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消