我需要按键从数据结构中检索项目。但我还要求使用键以外的字段按排序顺序遍历该数据结构。
像这样的东西(伪代码,仅用于说明目的):
var list = new SortedDictionary<TKey, TSortField, TItem>();
我该怎么做?有没有办法使用单一数据结构,还是我需要自己滚动?
注意: TItem
已经衍生自(和实施)IComparable<T>
。
答案 0 :(得分:2)
如果您不打算修改排序结果,可以使用IEnumerable.OrderBy和ToDictionary的组合:
var sortedResult = sortedDictionary.OrderBy(kvp => kvp.Value.SortField)
.ToDictionary(kvp => kvp.Key,
kvp => kvp.Value);
请记住,这实际上是在创建一个新的集合,而不是对原始集合进行排序(将在SortedDictionary中进行维护)。
答案 1 :(得分:2)
SortedDictionary类有一个Values property“获取包含SortedDictionary中值的集合”。该集合是IEnumerable,您可以对该值集合进行排序。
以下是C#中的一个示例程序(我作为示例快速编写了它。它可能会根据您的特定需求进行改进和/或更改。)
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
SortedDictionary<string, int> sd = new SortedDictionary<string, int>();
sd.Add("a", 10);
sd.Add("c", 4);
sd.Add("b", 20);
Console.WriteLine("___KEYS____");
foreach (string key in sd.Keys)
{
Console.WriteLine(key);
}
foreach(int sortedVal in sd.Values.OrderBy(value => value))
{
Console.WriteLine(sortedVal);
}
}
}
}
答案 2 :(得分:0)
将项目添加到SortedList只会存储对内存中已有对象的引用,因此不会占用更多空间。
答案 3 :(得分:0)
您可以使用LINQ对字典的Values属性进行排序,但如果列表很大或排序功能很昂贵,这可能比您希望的要慢 - 特别是如果您经常访问它。
这是我对排序字典的快速而又脏的实现。它使用Dictionary进行直接访问,但也保留ListDictionary实例以便对键或值进行有序访问。
您可以对任何字段或表达式进行排序。但是,如果排序包括方法调用,则函数应该是确定性的(因此,给定一组值,它们总是以相同的方式排序)。另请注意,项目在插入时进行排序 - 如果事后更新了对象,则排序顺序不会自动更新。如果这是可能的话,最好使用LINQ按需排序。
public class ArbitrarySortedDictionary<TKEY, TSORT, TVALUE> : IDictionary<TKEY, TVALUE>
where TSORT : IComparable
where TKEY : IComparable
{
/// <summary>
/// Key class for use in keeping the _SortedKeys and _SortedValues in proper order. Since the sorting
/// function could easily result in same values across instances, we'll use the key as secondary sort
/// field - since it's unique, everything should always have a consistent, unambiguous sort order.
/// </summary>
class SortedDictionaryKey
{
public SortedDictionaryKey(TSORT sortVal, TKEY key)
{
SortVal = sortVal;
Key = key;
}
public TSORT SortVal
{
get;
private set;
}
public TKEY Key
{
get;
private set;
}
}
readonly Func<TVALUE, TSORT> _SortFunc;
readonly Dictionary<TKEY, TVALUE> _InternalDict = new Dictionary<TKEY, TVALUE>();
readonly SortedList<SortedDictionaryKey, TKEY> _SortedKeys;
readonly SortedList<SortedDictionaryKey, TVALUE> _SortedValues;
public ArbitrarySortedDictionary(Func<TVALUE, TSORT> sortFunc)
{
_SortFunc = sortFunc;
Func<SortedDictionaryKey, SortedDictionaryKey, Int32> compFunc = (x, y) => {
Int32 sortValComp = 0;
if (x.SortVal != null)
sortValComp = x.SortVal.CompareTo(y.SortVal);
if (sortValComp != 0)
return sortValComp;
if (x.Key != null)
return x.Key.CompareTo(y.Key);
return y.Key == null ? 0 : -1;
};
var comparer = new LambdaComparer<SortedDictionaryKey>(compFunc);
_SortedKeys = new SortedList<SortedDictionaryKey, TKEY>(comparer);
_SortedValues = new SortedList<SortedDictionaryKey, TVALUE>(comparer);
}
public void Add(TKEY key, TVALUE value)
{
if (key == null)
throw new ArgumentException("Null key is not allowed.");
var sortKey = new SortedDictionaryKey(_SortFunc(value), key);
_InternalDict.Add(key, value);
_SortedKeys.Add(sortKey, key);
_SortedValues.Add(sortKey, value);
}
public bool ContainsKey(TKEY key)
{
return _InternalDict.ContainsKey(key);
}
public ICollection<TKEY> Keys
{
get {
return _SortedKeys.Values.ToList<TKEY>();
}
}
public bool Remove(TKEY key)
{
return RemoveInternal(key, _InternalDict[key]);
}
public bool TryGetValue(TKEY key, out TVALUE value)
{
return _InternalDict.TryGetValue(key, out value);
}
public ICollection<TVALUE> Values
{
get {
return _SortedValues.Values.ToList<TVALUE>();
}
}
public TVALUE this[Int32 index]
{
get {
return _InternalDict[_SortedKeys.Values[index]];
}
set {
throw new NotImplementedException("Can't update ArbitrarySortedDictionary directly.");
}
}
public TVALUE this[TKEY key]
{
get {
return _InternalDict[key];
}
set {
if (!ContainsKey(key)) {
Add(key, value);
return;
}
throw new NotImplementedException("To update items currently, remove and re-add.");
}
}
public void Add(KeyValuePair<TKEY, TVALUE> item)
{
var sortKey = new SortedDictionaryKey(_SortFunc(item.Value), item.Key);
_InternalDict.Add(item.Key, item.Value);
_SortedKeys.Add(sortKey, item.Key);
_SortedValues.Add(sortKey, item.Value);
}
public void Clear()
{
_SortedKeys.Clear();
_SortedValues.Clear();
_InternalDict.Clear();
}
public bool Contains(KeyValuePair<TKEY, TVALUE> item)
{
var val = _InternalDict[item.Key];
if (val == null)
return item.Value == null;
return val.Equals(item.Value);
}
public void CopyTo(KeyValuePair<TKEY, TVALUE>[] array, int arrayIndex)
{
Int32 curIndex = arrayIndex;
foreach (var item in this)
array[curIndex++] = item;
}
public int Count
{
get { return _InternalDict.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(KeyValuePair<TKEY, TVALUE> item)
{
return RemoveInternal(item.Key, item.Value);
}
public IEnumerator<KeyValuePair<TKEY, TVALUE>> GetEnumerator()
{
var res =
from k in _SortedKeys
join v in _SortedValues on k.Key equals v.Key
orderby k.Key
select new KeyValuePair<TKEY, TVALUE>(k.Value, v.Value);
return res.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private Boolean RemoveInternal(TKEY key, TVALUE val)
{
if (!_InternalDict.Remove(key))
return false;
var sortKey = new SortedDictionaryKey(_SortFunc(val), key);
var retVal = _SortedKeys.Remove(sortKey);
return retVal && _SortedValues.Remove(sortKey);
}
}
/// <summary>
/// Utility class - an IComparer based upon a lambda expression.
/// </summary>
public class LambdaComparer<T> : IComparer<T>
{
private readonly Func<T, int> _lambdaHash;
private readonly Func<T, T, int> _lambdaComparer;
public LambdaComparer(Func<T, T, int> lambdaComparer) :
this(lambdaComparer, o => 0)
{
}
public LambdaComparer(Func<T, T, int> lambdaComparer, Func<T, int> lambdaHash)
{
if (lambdaComparer == null)
throw new ArgumentNullException("lambdaComparer");
if (lambdaHash == null)
throw new ArgumentNullException("lambdaHash");
_lambdaHash = lambdaHash;
_lambdaComparer = lambdaComparer;
}
public int Compare(T x, T y)
{
return _lambdaComparer(x, y);
}
public int GetHashCode(T obj)
{
return _lambdaHash(obj);
}
}