将最新的键值对保留在排序列表中



我有一个每10分钟添加一次KeyValuePair的SortedList。我正在尝试保留最新的 10 个 KeyValuePair 并删除所有以前的对,但我正在做的事情不起作用。下面我附上了我的代码,并在每个步骤中进行了解释。任何帮助将不胜感激。

private SortedList<int, double> myList = new SortedList<int, double>();
        // Every 10 minutes a new KeyValuePair is added to myList so 
        // I have no issue with sorting. I'm only trying to get the most 
        // recent 10 KeyValuePairs.
        // My Attempt (the only one that worked without errors)
        int mylistCount = 10;
        if (myList.Count()>mylistCount)
        {myList.Clear();}
        // The issue with my attempt is that it erases the entire myList
        // As a result, whenever myList reaches 10, it goes back to Zero.
        // What I'm trying to do is keep myList Count at 10 containing only
        // the most recent KeyValuePairs.

**在myList中,Key int是PlayerID#(随机的(,值是玩家的得分%

要回答您的问题:

  • 排序不是当前设置的问题。
  • 它不一定是排序列表,我愿意接受任何建议。我只是更熟悉使用字典和列表。
  • 我从未使用过队列,但愿意尝试。(将不得不研究,我每天都在学习新东西(
  • 没有时间戳,新条目的时间并不重要。我要做的就是确保myList只有最近的10个。

我试图做的是将 myList 计数保持在 10 只包含 最新的键值对。

您想保留最近的 10 对,所以我假设排序是按加法时间进行的。如果这是真的,则无需对它们进行排序,因此不需要SortedList。您可以按照评论中的建议使用Queue

队列是先进先出 (FIFO(。这意味着您知道队列中的第一个元素是最古老的,并且当第十一个元素进入时需要取消排队。例如,这难道不能用很少的仪式来解决问题吗?

// q is a Queue (FIFO)
if (q.Count == 10)
{
    // we've reached our cap, remove the element at the 
    // front of the q (the oldest one)
    q.Dequeue();
}
// we'll always add the newest element to the end of the q
q.Enqueue(new KeyValuePair<int, double>(key, value));

使用LinkedList而不是SortedList怎么样?

if(myLinkedList.Count() > 10)
    myLinkedList.RemoveFirst();

这将始终删除列表中第一个添加的项目。

在不太了解密钥的情况下,我提供了一个简单的解决方案:

创建一个类来表示值及其添加时间,并实现IComparable<T>接口:

public class TimeStampedDouble  : IComparable<TimeStampedDouble>
{
    public TimeStampedDouble(double value)
    {
        Value = value;
        Date = DateTime.Now;
    }
    public double Value { get; private set; }
    public DateTime Date { get; private set; }
    public int CompareTo(TimeStampedDouble other)
    {
        return this.Date.CompareTo(other.Date);
    }
    // User-defined conversion to double, for convenience
    public static implicit operator double(TimeStampedDouble d)
    {
        return d.Value;
    } 
}

更改列表以改为存储此类型:

SortedList<int, TimeStampedDouble> list = new SortedList<int, TimeStampedDouble>();

使用新类将项目添加到列表中:

//In this line, 1 is the key, 6 is the double you are storing.
myList.Add(1, new TimeStampedDouble(6));
myList.Add(3, new TimeStampedDouble(5));
myList.Add(2, new TimeStampedDouble(4));
myList.Add(7, new TimeStampedDouble(3));
myList.Add(5, new TimeStampedDouble(2));

现在,您可以使用 Linq 获取最旧的项并将其删除:

if (myList.Count() > mylistCount)
{
    var oldest = myList.OrderByDescending(i => i.Value).FirstOrDefault();        
    myList.Remove(oldest.Key);
}

具有键5的项目将被删除。

没有必要检查oldest是否null,因为 a( 它是一种值类型和 b( 检查了最小数量的项目,因此假设列表将始终至少有一个项目,前提是mylistCount大于 0

由于提供了到 double 的隐式转换,因此可以在不显式强制转换的情况下使用该值:

double doubleValue = myList[7];

我认为最方便的解决方案是使用有界列表,以确保列表中的元素永远不会超过最大计数。实施这样的列表并不是很困难。可能最灵活的方法是实现IDictionary<TKey, TValue>接口,将工作委托给内部SortedList<TKey, TValue>。波纹管是一种基于继承的方法,需要更少的代码。每当添加的元素导致Count大于boundedCapacity时,列表中最早的元素就会自动删除。

public class BoundedSortedList<TKey, TValue> : SortedList<TKey, TValue>
{
    private readonly int _boundedCapacity;
    private readonly List<TKey> _queue = new List<TKey>();
    public BoundedSortedList(int boundedCapacity)
    {
        _boundedCapacity = boundedCapacity;
    }
    public new void Add(TKey key, TValue value)
    {
        base.Add(key, value);
        _queue.Add(key);
        if (this.Count > _boundedCapacity)
        {
            var keyToRemove = _queue[0];
            this.Remove(keyToRemove);
        }
    }
    public new TValue this[TKey key]
    {
        get { return base[key]; }
        set { this.Remove(key); this.Add(key, value); }
    }
    public new bool Remove(TKey key) { _queue.Remove(key); return base.Remove(key); }
    public new bool RemoveAt(int index) => throw new NotImplementedException();
    public new void Clear() { base.Clear(); _queue.Clear(); }
}

使用示例:

var myList = new BoundedSortedList<int, double>(10);

不正确的使用示例:

var myIList = (IDictionary<int, double>)myList;

这将不起作用,因为通过接口访问类将绕过使列表有界的逻辑。

以下是对我有用的方法:

if (myList.Count()>mylistCount)
{myList.Remove(myList.FirstOrDefault());}

谢谢大家

最新更新