2011-09-16 58 views
5

.NET似乎有很多數據結構和集合類型。它是否具有最大尺寸和不重複的先進先出集合,或類似的東西?最大尺寸且不重複的先進先出集合?

一個示例用法就像存儲5個最近打開的文件一樣。如果添加第6個對象,則將最少的對象退出以將大小保持爲5

+0

你有試過詞典,有排序能力嗎? –

+0

添加排隊散列集的代碼示例 –

+0

[如何在C#.NET中使用「FIFO」?](http://stackoverflow.com/questions/2966286/how-to-work-with-fifo- in-c-sharp-net) –

回答

3

您必須創建一個QueueSet實現ICollection<T>。它可以是包含收集作爲後備存儲的包裝類。它可以實現如下:

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(); 
    } 
} 

我將此代碼發佈到公有領域。

+0

一個評論,如果!queue.Contains(item),它應該重載該項目(使其成爲最近的一個) –

+0

我假設你的意思是Enqueue方法應該將項目移動到隊列頂部,如果該項目已經存在在Enqueue被調用的隊列中,我是對的嗎? –

+0

是的..這就是我的意思 –

1

您想要一個queue,否?

它並不真正支持最大大小和不重複,但可以從隊列繼承並添加這些功能。

你可以通過重載Enqueue方法來實現。像這樣的東西可能會奏效(但拋出更合適的異常類型!):

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類可能是這樣的:

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 
} 
+0

隊列允許重複並且沒有最大限制 –

+0

實際上,從.NET中的內置集合繼承是不實際的。沒有任何有用的方法被聲明爲「虛擬」,因此它們不能被擴展。 –

+0

@rtalbot:非通用版似乎工作,但延長'隊列'不起作用(因爲我已經突出顯示)。你真的應該使用'隊列',但我想這可能有效。 –

0

在這看看:Limit size of Queue<T> in .NET?

你基本上需要一個Queue,如果你管理,以限制其大小,並把它「索引」或「唯一」,那麼你都OK了:)

我相信圍繞Dictionary的一些邏輯也可以工作,你將存儲什麼數據類型?字符串?

+0

在這種情況下,是的,一個字符串。如何限制隊列項目是唯一的? –

0

這就是你想要的,HashQueue<T>,散列排隊集。

增加了一些線程鎖,可防止意外鎖定。請記住,所有HashSet操作都會破壞現有隊列的順序。

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); 
      //} 
     } 
    } 
}