Last extension method will give you the result, but it will have to enumerate the entire collection to get you there. It's such a shame SortedDictionary<K, V> doesn't expose Min and Max members especially considering internally it is backed by a SortedSet<KeyValuePair<K, V>> which has Min and Max properties.
If O(n) is not desirable, you have a few options:
Switch to a SortedList<K, V>. Again for some reason BCL doesn't pack this by default. You can use indexers to get max (or min) value in O(1) time. Extending with extension methods will be nice.
//Ensure you dont call Min Linq extension method.
public KeyValuePair<K, V> Min<K, V>(this SortedList<K, V> dict)
{
return new KeyValuePair<K, V>(dict.Keys[0], dict.Values[0]); //is O(1)
}
//Ensure you dont call Max Linq extension method.
public KeyValuePair<K, V> Max<K, V>(this SortedList<K, V> dict)
{
var index = dict.Count - 1; //O(1) again
return new KeyValuePair<K, V>(dict.Keys[index], dict.Values[index]);
}
Write your own SortedDictionary<K, V> class. This is very trivial. Have a SortedSet<KeyValuePair<K, V>> as the internal container and base the comparison on the Key part. Something like:
public class SortedDictionary<K, V> : IDictionary<K, V>
{
SortedSet<KeyValuePair<K, V>> set; //initialize with appropriate comparer
public KeyValuePair<K, V> Min { get { return set.Min; } } //O(log n)
public KeyValuePair<K, V> Max { get { return set.Max; } } //O(log n)
}
This is O(log n). Not documented, but I checked the code.
Use fiddly reflection to access the backing set which is private member of SortedDictionary<K, V> class and invoke Min and Max properties. One can rely on expressions to compile a delegate and cache it for performance. It's a very poor choice to do so. Can't believe I suggested this.
As folks have already pointed Last extension will enumerate the entire collection, its impact on perf can be deadly.
Just to remove 10000 last elements from SortedDict, it took a lot more time than similar operation on SortedSet.
SortedSet Removal Elapsed ms : 8
SortedDict Removal Elapsed ms : 3697
// In below code,ss is SortedSet and sd is SortedDictionary and both contain same 10000 elements.
sw.Start();
while (ss.Count != 0)
{
ss.Remove(ss.Max);
}
sw.Stop();
Console.WriteLine("SortedSet Removal Elapsed ms : {0}", sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
while (sd.Count != 0)
{
sd.Remove(sd.Keys.Last());
}
sw.Stop();
Console.WriteLine("Dict Removal Elapsed ms : {0}", sw.ElapsedMilliseconds);
发布评论
评论(5)
Last
扩展方法将为您提供结果,但它必须枚举整个集合才能到达该结果。遗憾的是SortedDictionary
没有公开Min
和Max
成员,特别是考虑到它在内部由支持SortedSet>
具有Min
和Max
属性。如果 O(n) 不理想,您有几个选择:
切换到
SortedList
。出于某种原因,BCL 再次默认不打包此内容。您可以使用索引器在 O(1) 时间内获取最大值(或最小值)。使用扩展方法进行扩展会很好。SortedList
还带有其他惩罚。因此,您可能想查看:SortedList 和 SortedDictionary 之间有什么区别?编写您自己的
SortedDictionary
类。这是非常微不足道的。使用SortedSet>
作为内部容器,并基于Key
部分进行比较。类似于:这是 O(log n)。没有记录,但我检查了代码。
使用繁琐的反射来访问作为
SortedDictionary
类的私有成员的支持集,并调用Min
和Max
属性。人们可以依靠表达式来编译委托并缓存它以提高性能。这样做是一个非常糟糕的选择。不敢相信我建议这样做。依赖其他实现,例如。对于
TreeDictionary ;
来自C5。他们有FindMin
和FindMax
两者都是 O(log n)Last
extension method will give you the result, but it will have to enumerate the entire collection to get you there. It's such a shameSortedDictionary<K, V>
doesn't exposeMin
andMax
members especially considering internally it is backed by aSortedSet<KeyValuePair<K, V>>
which hasMin
andMax
properties.If O(n) is not desirable, you have a few options:
Switch to a
SortedList<K, V>
. Again for some reason BCL doesn't pack this by default. You can use indexers to get max (or min) value in O(1) time. Extending with extension methods will be nice.SortedList<K, V>
comes with other penalties. So you might want to see: What's the difference between SortedList and SortedDictionary?Write your own
SortedDictionary<K, V>
class. This is very trivial. Have aSortedSet<KeyValuePair<K, V>>
as the internal container and base the comparison on theKey
part. Something like:This is O(log n). Not documented, but I checked the code.
Use fiddly reflection to access the backing set which is private member of
SortedDictionary<K, V>
class and invokeMin
andMax
properties. One can rely on expressions to compile a delegate and cache it for performance. It's a very poor choice to do so. Can't believe I suggested this.Rely on other implementations, for eg. For
TreeDictionary<K, V>
from C5. They haveFindMin
andFindMax
both of which are O(log n)您可以使用 LINQ:
您还可以获取最后一个键:
您甚至可以获取最后一个键值对:
这将为您提供一个
KeyValuePair
和Key
和Value
属性。请注意,如果字典为空,这将引发异常;如果您不希望这样,请调用
LastOrDefault
。You can use LINQ:
You can also get the last key:
You can even get the last key-value pair:
This will give you a
KeyValuePair<TKey, TValue>
withKey
andValue
properties.Note that this will throw an exception if the dictionary is empty; if you don't want that, call
LastOrDefault
.您可以使用
SortedDictionary.Values.Last();
或者如果您想要键和值
You can use
SortedDictionary.Values.Last();
or if you want the key and the value
排序列表列表...
SortedList list...
正如人们已经指出的Last扩展将枚举整个集合,它对性能的影响可能是致命的。
仅从 SortedDict 中删除最后 10000 个元素,就比 SortedSet 上的类似操作花费更多时间。
排序集删除已用毫秒:8
SortedDict 删除已用毫秒:3697
// 在下面的代码中,ss 是 SortedSet,sd 是 SortedDictionary,并且都包含相同的 10000 个元素。
As folks have already pointed Last extension will enumerate the entire collection, its impact on perf can be deadly.
Just to remove 10000 last elements from SortedDict, it took a lot more time than similar operation on SortedSet.
SortedSet Removal Elapsed ms : 8
SortedDict Removal Elapsed ms : 3697
// In below code,ss is SortedSet and sd is SortedDictionary and both contain same 10000 elements.