将最新的 KeyValuePairs 保存在 SortedList 中

Keep the most recent KeyValuePairs in a SortedList

我有一个 SortedList,每 10 分钟添加一次 KeyValuePairs。我试图保留最近的 10 个 KeyValuePairs 并删除所有先前的对,但我正在做的事情不起作用。下面我附上了我的代码,并对每个步骤进行了解释。非常感谢任何帮助。

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#(随机),Value 是玩家的分数 %

回答您的问题:

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

创建一个class来表示值以及添加的时间并实现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>();

使用新 class:

添加项目到列表
//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];

What I'm trying to do is keep myList Count at 10 containing only the most recent KeyValuePairs.

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

队列是先进先出(FIFO)。这意味着您知道队列中的第一个元素是最旧的,并且当第 11 个元素进入时您需要将其出队。例如,这不能用一点仪式来解决问题吗?

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

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

我认为最方便的解决方案是使用有界列表,以确保列表中的元素永远不会超过最大计数。实施这样的列表并不困难。可能最灵活的方法是实现 IDictionary<TKey, TValue> 接口,将工作委托给内部 SortedList<TKey, TValue>。 Bellow 是一种 inheritance-based 方法,它需要更少的代码。每次添加的元素导致 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;

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

以下是对我有用的方法:

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

谢谢大家