views:

68

answers:

6

I have a list that I want to be able to store 20 values. What would be a good approach to deleting older values. A better example would be, imagine a change history and I wan't to be able to store 20 latest changes, while older ones go away.

Is there a special thing in C# that will let me do that or do I have to either make my own or use the Remove function.

EDIT1: Alright, how about storing 4000 - 10000 values, suddenly a linked-list looks attractive.

EDIT2: Circular list is good BUT, I don't want to be able to loop my older values.

EDIT3: For my problem, random access isn't too important, but sequential access is.

+2  A: 

use a Queue. each time you enqueue into the queue check if size == 20. If so, dequeue/pop one element

Armen Tsirunyan
And lose random access?
SLaks
@SLaks: If random access is not needed, then yes, lose it, otherwise my answer is bad :)
Armen Tsirunyan
Using a queue, you cannot get access to anything but the first element.
SLaks
A: 

There is no built in collection that handles that, but you could easily make one:

public class LimitedList<T> : List<T> {

  public new void Add(T item) {
    if (Count == 20) {
      RemoveAt(0);
    }
    base.Add(item);
  }

}

Note though that this currently only handles the limit when items are added using the Add method, and not other methods like AddRange and Insert. Also, as SLask pointed out, the List<T> class isn't specifically intended to be inherited (although it's not marked as final), so a more robust implementation would encapsulate the list instead of inheriting from it.

Note also that it's inefficient to remove the first item in a large list, but with as few items as 20, there is no problem. A LinkedList would handle that better if you need a much larger collection.

Guffa
This is bad design; the `IList<T>` implementation will not be affected. http://msdn.microsoft.com/en-us/library/ms182142%28VS.80%29.aspx
SLaks
@SLaks: Good point, that's also a limitation of the implementation that should be mentioned. A more robust implementation would be to simply encapsulate the list instead of inheriting from it, but then you have to implement some more methods and properties to be able to access the items in the list.
Guffa
@Guffa, Why use this? use Q instead this, also where is the randomly removing items.
SaeedAlg
@SaeedAlg: What are you talking about? Who would want randomly removing items?
Guffa
@Guffa, Sorry i didn't read question carefully (i think he want to remove older items with higher probability, see my answer), I didn't read it to end because I see some K people answered the question and i can't think about a simple problem as this should be here. but why you using List :D
SaeedAlg
+1  A: 

Sounds like you're describing a ring buffer. http://stackoverflow.com/questions/590069/how-would-you-code-an-efficient-circular-buffer-in-java-or-c might be helpful.

Cameron Skinner
Yes, a circular buffer is efficient for this kind of things, but it might be overkill for such a small collection.
Guffa
Overkill? Mate, in my day, we didn't shy away from an algorithm just because your namby-pamby, wet-nurse, "Can I change your daipers for you?" language didn't provide them in its standard library. A circular buffer is _exactly_ the right answer here. Now get off my lawn :-)
paxdiablo
I love that commercial, but in all seriousness, you're absolutely right, and since when did implementing an algorithm became hard, a little effort goes a long way, after all...
Dave
@paxdiablo: It would be irresponsible to use an overly complicated algorithm to solve a problem, when there is a perfectly fine implementation already existing in the framework, unless you are paying for your time yourself and can use it for any pet project you like.
Guffa
OK, so after your edits I have a question. How do you decide what "old" is? Do you want the n most recent items, or do you want at most n items that have changed inside some time horizon? If you want the former then a ring buffer (aka circular list) is what you should probably use. If you want the second then things get a bit more complex.
Cameron Skinner
By the way, how is a circular list "overkill" compared to maintaining a queue, checking its size and popping the head? A circular list does *exactly* that but much, much easier. It's not terribly complicated if you don't need random access.
Cameron Skinner
@Guffa, a circular buffer would take all of about ten minutes to implement from scratch (and I rarely do that since I have a huge stockpile of code from previous work to draw on).
paxdiablo
A: 

You can make your own list class:

public class BoundedList<T> : Collection<T> {
    public int MaxSize { get; private set; }
    public BoundedList(int MaxSize) : base(new List<T>(maxSize)) {
        MaxSize = maxSize;
    }
    protected override void InsertItem(T item, int index) {
        base.InsertItem(item, index)
        if (Count > MaxSize)
            Remove(0);
    }
}
SLaks
A: 

I think you need priority Q and you can define priority randomly. before adding each item, increase remained items priority.

SaeedAlg
A: 

Alright I finally got a chance to think about this problem myself and found a good compromise without going through too much effort. Why not just use a linked list.

  1. For a history type of implementation, just keep track of the pointer.
  2. It will still be linear time for sequencing operations.
  3. Removing the last value can be done in constant time.

I guess I failed to mention that random access wasn't too important...

Dave