可以使用SortedList<> / SortedDictionary<>使用正确实现的比较器来保证插入顺序?

时间:2013-12-09 20:59:20

标签: c# dictionary hashtable sortedlist sorteddictionary

如果目标是创建一个保留插入顺序的通用只读字典,可以使用SortedList<,>或SortedDictionary<,>实际上可以与IComparer一起使用<>尝试通过执行类似以下的操作来维护插入顺序?

class OrderedComparer<T> : IComparer<M>
{
    public int Compare(M x, M y)
    {
        return x.Equals(y) ? 0 : -1;//or 1
    }
}
SortedList<M> orderedList = new SortedList<M>(new OrderedComparer<T>());

(有趣的是,在SortedDictionary的情况下,上面的方法需要返回0或1以防止元素按反向插入顺序排序。)

3 个答案:

答案 0 :(得分:5)

比较者必须遵守法律

Compare(a, b) == -Compare(b, a) //assuming only possible values are -1, 0, 1

这是symmetry property。您的示例代码不遵守它。因此BCL系列根本不给您任何保证。您违反了记录的合同。

你不能这样做。

相反,您可以将新字段添加到M,并将广告订单存储为int。然后,您可以在比较器中使用该字段。

答案 1 :(得分:3)

Compare实施不遵循它应该遵循的rules of symmetry。这不是解决这个问题的正确方法。

对于按插入顺序排序的列表,只需使用List<T>作为实现。另一方面,使用Dictionary<,>,“返回项目的顺序未定义”。您可以将自己的IDictionary<,>实现一起使用这两个类来完成您正在尝试的操作。

public class MyInsertionOrderDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    private List<TKey> keysList;
    private Dictionary<TKey, TValue> dict;

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        foreach (TKey key in keysList)
        {
            TValue value = dict[key];
            yield return new KeyValuePair<TKey, TValue>(key, value);
        }
    }

    // TODO implement interface
    // when adding:
    // keysList.Add(key);
    // dict.Add(key, value);

    // when removing:
    // keysList.Remove(key);
    // dict.Remove(key);

    // you could also implement an indexer property like
    public KeyValuePair<TKey, TValue> this[int index] { get { ... } }
}

这个类在外部非常类似于OrderedDictionary类,但它是通用的。那里有other generic implementations

答案 2 :(得分:0)

毫无疑问,你应该做这么可怕的事情。出于各种完美的理由,你绝对不应该这样:

  • 不要将已排序的容器用于未排序的数据
  • 这不是您使用比较器的方式
  • 避免依赖您不拥有的图书馆的实施细节

现在,要实际知道您是否可以通过黑客攻击比较器保留SortedList中的插入顺序,只有一种方法:查看实现。反编译字节码,看看它是否可行。

事实证明,SortedList使用二进制搜索,SortedDictionary使用红黑树。

愚弄二进制搜索很容易。比较器仅用于比较新项目(如果您不删除任何内容)。总是返回1或-1,我总是忘记哪一个,并且你有一个未排序的列表。

对于红黑树,我不确定相同的技巧是否有效。我不记得那种树在重新平衡时是否必须使用比较器。如果确实如此,比较器无法提供有意义的结果可能会导致运行时错误,或者至多会导致复杂性保证丢失。但也许它真的很好。除此之外,我认为你仍然可以获得最大程度的再平衡。