有没有办法跟踪字典中项目的顺序?

时间:2010-03-03 16:08:59

标签: c# .net dictionary hashtable

我有Dictionary<Guid, ElementViewModel>。 (ElementViewModel是我们自己的复杂类型。) 我使用库存标准items.Add(Guid.NewGuid, new ElementViewModel() { /*setters go here*/ });

将项目添加到字典中

稍后我会删除部分或全部这些项目。

我的ElementViewModel的简单视图是:

class ElementViewModel
{
    Guid Id { get; set; }
    string Name { get; set; }
    int SequenceNo { get; set; }
}

值得注意的是,如果发生移动和复制等其他操作,则在添加后,SequenceNos会在集合中进行压缩。 {1,5,6} - &gt; {1,2,3}

我的删除操作的简单视图是:

public void RemoveElementViewModel(IEnumerable<ElementViewModel> elementsToDelete)
{
    foreach (var elementViewModel in elementsToDelete)
        items.Remove(elementViewModel.Id);

    CompactSequenceNumbers();
}

我将用一个例子说明问题:

我在字典中添加了3个项目:

var newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 1, Name = "Element 1" });
newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 2, Name = "Element 2" });
newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 3, Name = "Element 3" });

我删除了2项

RemoveElementViewModel(new List<ElementViewModel> { item2, item3 }); //imagine I had them cached somewhere.

现在我想添加2个其他项目:

newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 2, Name = "Element 2, Part 2" });
newGuid = Guid.NewGuid();
items.Add(newGuid, new MineLayoutElementViewModel { Id = newGuid, SequenceNo = 3, Name = "Element 3, Part 2" });

此时对字典的评价,我期望项目的顺序 “元素1”,“元素2,第2部分”,“元素3,第2部分”

但它实际上按以下顺序排列: “元素1”,“元素3,第2部分”,“元素2,第2部分”


我依赖这些项目的顺序是某种方式。为什么它不符合预期,我该怎么办?

3 个答案:

答案 0 :(得分:14)

.Net词典在设计上是无序的。

您应该使用KeyedCollection<TKey, TValue>代替;它将保留项目添加到集合的顺序,并且还将使用哈希表进行快速查找。

例如:

class ElementViewModelCollection : KeyedCollection<Guid, ElementViewModel> {
    protected override Guid GetKeyForItem(ElementViewModel item) { return item.Id; }
}

items.Add(new MineLayoutElementViewModel { Id = Guid.NewGuid(), SequenceNo = 3, Name = "Element 3" });

请注意,如果在将项添加到集合后更改Id属性,则需要在集合上调用ChangeItemKey方法。我强烈建议您将Id属性设置为只读。

答案 1 :(得分:3)

你没有使用System.Collections.Generic.SortedDictionary的任何理由,看起来像你在寻找

答案 2 :(得分:0)

不幸的是,SortedDictionary对于我们必须存储的大量数据来说还不够快,并且KeyedCollection无法手动压缩元素的SequenceNo属性。

严格来说,我们应该重写排序的方式,因为我的解决方案不是最漂亮的:

每次删除某个项目时,都会新建该词典并将未删除的项目重新添加到新建词典中,以保持默认顺序。 - &GT;我承认,这是一种可怕的做法。一旦压力减小,就计划改变它。