Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dictionary element accessing

Tags:

c#

.net

Question

Must looping through all C# Dictionary elements be done only through foreach, and if so why?

Or, I could ask my question as: can Dictionary elements be accessed by position within the Dictionary object (i.e., first element, last element, 3rd from last element, etc)?

Background to this question

I'm trying to learn more about how Dictionary objects work, so I'd appreciate help wrapping my mind around this. I'm learning about this, so I have several thoughts that are all tied into this question. I'll try to present in a way that is appropriate for SO format.

Research

In a C# array, elements are referenced by position. In a Dictionary, values are referenced by keys.

Looking through the documentation on MSDN, there are the statements

"For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair structure representing a value and its key. The order in which the items are returned is undefined."

So, it would seem that since the order items are returned in is undefined, there is no way to access elements by position. I also read:

"Retrieving a value by using its key is very fast, close to O(1), because the Dictionary class is implemented as a hash table."

Looking at the documentation for the HashTable .NET 4.5 class, there is reference to using a foreach statement to loop through and return elements. But there is no reference to using a for statement, or for that matter while or any other looping statement.

Also, I've noticed Dictionary elements use the IEnumerable interface, which seems to use foreach as the only type of statement for looping functions.

Thoughts

So, does this mean that Dictionary elements cannot be accessed by "position," as arrays or lists can?

If this is so, why is there a .Count property that returns the number of key/value pairs, yet nothing that lets me reference these by nearness to the total? For example, .Count is 5, why can't I request key/value pair .Count minus 1?

How is foreach able to loop over each element, yet I have no access to individual elements in the same way?

Is there no way to determine the position of an element (key or value) in a Dictionary object, without utilizing foreach? Can I not tell, without mapping elements to a collection, if a key is the first key in a Dictionary, or the last key?

This SO question and the excellent answers touch on this, but I'm specifically looking to see if I must copy elements to an array or other enumerable type, to access specific elements by position.

Here's an example. Please note I'm not looking for a way to specifically solve this example - it's for illustration purposes of my questions only. Suppose I want to add all they keys in a Dictionary<string, string> object to a comma-separated list, with no comma at the end. With an array I could do:

string[] arrayStr = new string[2] { "Test1", "Test2" };
string outStr = "";
for (int i = 0; i < arrayStr.Length; i++)
{
    outStr += arrayStr[i];
    if (i < arrayStr.Length - 1)
    {
        outStr += ", ";
    }
}

With Dictionary<string, string>, how would I copy each key to outStr using the above method? It appears I would have to use foreach. But what Dictionary methods or properties exist that would let me identify where an element is located at, within a dictionary?

If you're still reading this, I also want to point out I'm not trying to say there's something wrong with Dictionary... I'm simply trying to understand how this tool in the .NET framework works, and how to best use it myself.

like image 902
Aaron Thomas Avatar asked Apr 21 '15 16:04

Aaron Thomas


1 Answers

Say you have four cars of different colors. And you want to be able to quickly find the key to a car by its color. So you make 4 envelopes labelled "red", "blue", "black", and "white" and place the key to each car in the right envelope. Which is the "first" car? Which is the "third"? You're not concerned about the order of the envelopes; you're concerned about being able to quickly get the key by the color.

So, does this mean that Dictionary elements cannot be accessed by "position," as arrays or lists can?

Not directly, no. You can use Skip and Take but all they will do is iterate until you get to the "nth" item.

If this is so, why is there a .Count property that returns the number of key/value pairs, yet nothing that lets me reference these by nearness to the total? For example, .Count is 5, why can't I request key/value pair .Count minus 1?

You can still measure the number of items even thought there's no order. In my example you know there are 4 envelopes, but there's no concept of the "third" envelope.

How is foreach able to loop over each element, yet I have no access to individual elements in the same way?

Because foreach use IEnumerable, which just asks for the "next" element each time - the underlying collection determines what order the elements are returned in. You can pick up the envelopes one by one, but the order is irrelevant.

Is there no way to determine the position of an element (key or value) in a Dictionary object, without utilizing foreach?

You can infer it by using foreach and counting how many elements you have before reaching the one you want, but as soon as you add or remove an item, that position may change. If I buy a green car and add the envelope, where in the "order" would it go?

I'm specifically looking to see if I must copy elements to an array or other enumerable type, to access specific elements by position.

Well, no, you can use Skip and Take, but there's no way to predict what item is at that location. You can pick up two envelopes, ignore them, pick up another one and call it the "third" envelope, but so what?

like image 138
D Stanley Avatar answered Sep 30 '22 04:09

D Stanley