2011-09-16 8 views
5

.NET sembra avere molti tipi di struttura e raccolta dati. Ha una collezione first-in-first-out con una dimensione massima e nessuna duplicazione, o qualcosa di simile?Collezione first-in-first-out con dimensioni massime e senza duplicazione?

Un esempio di utilizzo sarebbe come per la memorizzazione di 5 file aperti più di recente. Se viene aggiunto un sesto oggetto, deseleziona l'oggetto meno recente per mantenere la dimensione su 5

+0

Forse hanno provato Dizionario , con funzionalità di ordinamento? –

+0

Esempio di codice aggiunto di un set di hash in coda –

+0

Possibile duplicato di [Come lavorare con "FIFO" in C# .NET?] (Http://stackoverflow.com/questions/2966286/how-to-work-with-fifo- in-c-sharp-net) –

risposta

3

È necessario creare un QueueSet che implementa ICollection<T>. Può essere una classe wrapper che contiene una raccolta come backing store. Può essere implementato come segue:

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

Io rilascio questo codice nel pubblico dominio.

+0

un commento, se! Queue.Contains (elemento), dovrebbe riaccodare l'elemento (per renderlo il più recente) –

+0

Presumo intendi che il metodo Enqueue dovrebbe spostare l'elemento in cima alla coda se l'elemento esiste già in coda quando viene chiamato Enqueue, ho ragione? –

+0

sì .. questo è quello che intendo –

1

Vuoi un queue, no?

In realtà non supporta la dimensione massima e nessuna duplicazione, ma è possibile ereditare da Coda e aggiungere tali funzioni.

È possibile farlo sovrascrivendo il metodo Enqueue. Qualcosa di simile potrebbe funzionare (ma gettare più appropriati tipi di eccezione!):

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 contenente o involucro o HA-Una classe potrebbe assomigliare a questo:

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

una coda consente duplicati e non ha una limitazione massima –

+0

In realtà, l'ereditarietà delle raccolte predefinite in .NET non è pratica. Nessuno dei metodi utili è dichiarato 'virtuale', quindi non possono essere estesi. –

+0

@rtalbot: La versione non generica sembra funzionare, ma l'estensione di 'Queue ' non funziona (per il motivo che ho già evidenziato). Dovresti davvero usare 'Queue ', ma suppongo che questo potrebbe funzionare. –

0

un'occhiata a questo: Limit size of Queue<T> in .NET?

è fondamentalmente bisogno di un Queue, se si riesce a limitare la sua dimensione e farlo "indicizzato" o "unico", allora si sono ok :)

I credo che un po 'di logica attorno a un Dictionary funzionerebbe anche, qual è il tipo di dati che verranno memorizzati? Stringhe?

+0

In questo caso, sì, una stringa. Come limitare gli articoli in coda per essere unici? –

0

Questo è ciò che si desidera, HashQueue<T>, il set con hash in coda.

Sono state aggiunte alcune chiusure a filo, proteggono dalle serrature accidentali. Tenere presente che tutte le operazioni di hashset interrompono l'ordine della coda esistente.

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