Use dictionary instead of List get ith entry

Perhaps I am just having my dumb moment right now. I have the following:

List<DirectoryEntry> list = new List<DirectoryEntry>();
List.Add(startEntry);
int i=0;
while(i < list.Count) {
    DirectoryEntry entry = list[i];
    foreach(DirectoryEntry child in GetChildEntries(entry)) {
        if(!list.Contains(child)) // Do not add if entry already in list!
            list.Add(child);
    }
}

This does not work because Contains somehow returns false for two directoryEntries that point to the same AD object.

So I thought to make a Dictionary from that and store the distinguishedName along with the entry:

Dictionary<string,DirectoryEntry> list = new Dictionary<string,DirectoryEntry>();
List.Add(startEntry.Properties["distinguishedName"].Value,startEntry);
int i=0;
while(i < list.Count) {
    DirectoryEntry entry = list[i]; // Does not work, because the index is a string here.
                                    // How to get the ith entry from the dictionary?
    foreach(DirectoryEntry child in GetChildEntries(entry)) {
        var dn = child.Properties["distinguishedName"].Value;
        if(!list.ContainsKey(dn)) list.Add(dn,child);
    }
}

The question, as stated in the code comment:

How to get the ith entry from the dictionary?

Jon Skeet
people
quotationmark

Well you can use list.ElementAt(i) to get the ith element in the order they happen to be returned by the dictionary - but there's no guarantee as to what order that is, or that it will stay consistent over time. I would strongly recommend avoiding thinking of a dictionary has having any concept of order.

It seems to me that you just need to iterate over the dictionary though:

foreach (var entry in list)
{
    ...
}

That leads to another problem though, which is that you're modifying the collection you're iterating over while you're iterating over it, which will fail. You might want to consider creating a new dictionary while you're iterating, and then add all the entries to the original one afterwards.

It's unclear whether you really want a dictionary or not though. We don't know what you're really trying to achieve - there are many different options here.

EDIT: If you want to flatten, you could do something like:

var entries = new Dictionary<string, DirectoryEntry>();
var queue = new Queue<DirectoryEntry>();
queue.Enqueue(startEntry);
while (queue.Count > 0)
{
    var candidate = queue.Dequeue();
    string key = candidate.Properties["distinguishedName"].Value;
    if (!entries.ContainsKey(key))
    {
        entries[key] = candidate;
        foreach (var child in GetChildEntries(candidate))
        {
            queue.Enqueue(child);
        }
    }
}

You could "hide" the foreach loop by creating your own EnqueueAll extension method on Queue<T>, if you wanted.

This feels to me like simpler code to understand than iterating over a collection you're still adding to.

EDIT: And if you don't need to look up by distinguished name later, you can use a HashSet<DirectoryEntry> with a custom equality comparer:

var entries = new HashSet<DirectoryEntry>(new DirectoryEntryEqualityComparer());
var queue = new Queue<DirectoryEntry>();
queue.Enqueue(startEntry);
while (queue.Count > 0)
{
    if (entries.Add(candidate))
    {
        foreach (var child in GetChildEntries(candidate))
        {
            queue.Enqueue(child);
        }
    }
}

people

See more on this question at Stackoverflow