将最新的 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 是玩家的分数 %
回答您的问题:
- 排序不是当前设置的问题。
- 它不一定是 SortedList,我愿意接受任何建议。我只是更熟悉使用字典和列表。
- 我从未使用过 Queue,但愿意尝试。 (必须研究一下,我每天都在学习新东西)
- 没有时间戳,新条目的时间并不重要。我要做的就是确保 myList 只有最近的 10 个。
在不太了解密钥的情况下,我提供一个简单的解决方案:
创建一个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());}
谢谢大家
我有一个 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 是玩家的分数 %
回答您的问题:
- 排序不是当前设置的问题。
- 它不一定是 SortedList,我愿意接受任何建议。我只是更熟悉使用字典和列表。
- 我从未使用过 Queue,但愿意尝试。 (必须研究一下,我每天都在学习新东西)
- 没有时间戳,新条目的时间并不重要。我要做的就是确保 myList 只有最近的 10 个。
在不太了解密钥的情况下,我提供一个简单的解决方案:
创建一个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());}
谢谢大家