Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to keep track of the ordering of items in a dictionary?

I have a Dictionary<Guid, ElementViewModel>. (ElementViewModel is our own complex type.) I add items to the dictionary with a stock standard items.Add(Guid.NewGuid, new ElementViewModel() { /*setters go here*/ });,

At a later stage I remove some or all of these items.

A simplistic view of my ElementViewModel is this:

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

It may be significant to mention that the SequenceNos are compacted within the collection after adding, in case other operations like moving and copying took place. {1, 5, 6} -> {1, 2, 3}

A simplistic view of my remove operation is:

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

    CompactSequenceNumbers();
}

I will illustrate the problem with an example:

I add 3 items to the dictionary:

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" });

I remove 2 items

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

Now I want to add 2 other items:

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" });

On evaluation of the dictionary at this point, I expected the order of items to be "Element 1", "Element 2, Part 2", "Element 3, Part 2"

but it is actually in the following order: "Element 1", "Element 3, Part 2", "Element 2, Part 2"


I rely on the order of these items to be a certain way. Why is it not as expected and what can I do about it?

like image 293
Corpsekicker Avatar asked Mar 03 '10 16:03

Corpsekicker


People also ask

Does dictionary preserve order?

Standard dict objects preserve order in the reference (CPython) implementations of Python 3.5 and 3.6, and this order-preserving property is becoming a language feature in Python 3.7. You might think that this change makes the OrderedDict class obsolete.

Are items in dictionary ordered?

In general dictionaries are not sorted. They are grouped by key/value pairs.

Do dictionary keys have an order?

Answer. No, there is no guaranteed order for the list of keys returned by the keys() function. In most cases, the key list is returned in the same order as the insertion, however, that behavior is NOT guaranteed and should not be depended on by your program.

How do you sort a dictionary?

It is not possible to sort a dictionary, only to get a representation of a dictionary that is sorted. Dictionaries are inherently orderless, but other types, such as lists and tuples, are not. So you need an ordered data type to represent sorted values, which will be a list—probably a list of tuples.


1 Answers

.Net Dictionaries are unordered by design.

You should use a KeyedCollection<TKey, TValue> instead; it will preserve the order that items are added to the collection and will also use a hash table for speedy lookups.

For example:

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" });

Note that if you change the Id property after the item is added to the collection, you'll need to call the ChangeItemKey method on the collection. I highly recommend that you make the Id property read-only.

like image 162
SLaks Avatar answered Oct 19 '22 03:10

SLaks