2011-09-16 33 views
5

.NET dường như có nhiều cấu trúc dữ liệu và các loại bộ sưu tập. Liệu nó có một bộ sưu tập đầu tiên trong lần đầu tiên với kích thước tối đa và không có sự trùng lặp, hoặc một cái gì đó tương tự như vậy?Bộ sưu tập đầu tiên-ra-trước với kích thước tối đa và không sao chép?

Ví dụ về cách sử dụng sẽ giống như lưu trữ 5 tệp được mở gần đây nhất. Nếu đối tượng thứ 6 được thêm vào, hãy dequeue đối tượng gần đây nhất để giữ kích thước thành 5

+0

Bạn đã thử từ điển , với khả năng sắp xếp? –

+0

Đã thêm mẫu mã của một bộ băm xếp hàng đợi –

+0

Có thể trùng lặp của [Cách làm việc với "FIFO" trong C# .NET?] (Http://stackoverflow.com/questions/2966286/how-to-work-with-fifo- in-c-sharp-net) –

Trả lời

3

Bạn sẽ phải tạo một QueueSet triển khai ICollection<T>. Nó có thể là một lớp bao bọc có chứa một bộ sưu tập như một cửa hàng sao lưu. Nó có thể được thực hiện như sau:

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

Tôi phát hành mã này vào phạm vi công cộng.

+0

một bình luận, nếu! Queue.Contains (item), nó nên requeue mục (để làm cho nó gần đây) –

+0

Tôi giả sử bạn có nghĩa là phương pháp Enqueue nên di chuyển mục lên đầu hàng đợi nếu mục đã tồn tại trong hàng đợi khi Enqueue được gọi, tôi có đúng không? –

+0

vâng .. đó là ý tôi là –

1

Bạn muốn có một queue, không?

Nó không thực sự hỗ trợ kích thước tối đa và không trùng lặp nhưng bạn có thể kế thừa từ Hàng đợi và thêm các tính năng đó.

Bạn có thể làm như vậy bằng cách ghi đè phương pháp Enqueue. Một cái gì đó như thế này có thể làm việc (nhưng ném các loại ngoại lệ thích hợp hơn!):

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

Một chứa hoặc wrapper hoặc ĐÃ-Một lớp học có thể trông như thế này:

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

một hàng đợi cho phép trùng lặp và không có giới hạn tối đa –

+0

Thực ra, kế thừa từ các bộ sưu tập tích hợp trong .NET là không thực tế. Không có phương thức hữu ích nào được khai báo là 'virtual', vì vậy chúng không thể được mở rộng. –

+0

@rtalbot: Phiên bản không chung chung có vẻ như workg, nhưng việc mở rộng 'Queue ' không hoạt động (vì lý do tôi đã làm nổi bật). Bạn thực sự nên sử dụng 'Queue ', nhưng tôi cho rằng điều này có khả năng có thể hoạt động. –

0

có một cái nhìn tại đây: Limit size of Queue<T> in .NET?

về cơ bản bạn cần một Queue, nếu bạn quản lý để hạn chế kích thước của nó và làm cho nó "lập chỉ mục" hoặc "độc đáo", sau đó bạn là ok :)

tôi tin rằng một chút logic xung quanh một Dictionary cũng sẽ hoạt động, loại dữ liệu bạn sẽ lưu trữ là gì? Dây?

+0

Trong trường hợp này, có, một chuỗi. Làm thế nào để hạn chế các mục hàng đợi là duy nhất? –

0

Đây là những gì bạn muốn, HashQueue<T>, bộ được xếp hàng đợi được băm.

Đã thêm một số khóa chủ đề, bảo vệ khỏi các khóa tình cờ. Hãy nhớ rằng tất cả các hoạt động HashSet đều phá vỡ thứ tự của hàng đợi hiện có.

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); 
      //} 
     } 
    } 
} 
Các vấn đề liên quan