How to iterate over a dictionary?

Asked

Viewed 2,680 times

4

I have seen several ways to iterate over a dictionary. There is one considered standard?

  • As the question was marked by not being clear enough, and no one has spoken out in support of why, either informally or citing the help desk documents, I will request reopening.

  • 2
  • 1

    For those who want to vote for closure, first see in the history that it has already been closed and reopened by a moderator. In addition, it is being discussed at the goal: http://meta.pt.stackoverflow.com/q/5399/132 - So, please, do not vote to close without putting forward strong arguments to do so.

  • 1

    @J.Guilherme Did any of the answers solve your question? Do you think you can accept one of them? Check out the [tour] how to do this, if you haven’t already done so. You would help the community by identifying what was the best solution for you. You can accept only one of them. But you can vote on any question or answer you find useful on the entire site

3 answers

8

Yes, there is.

The dictionary and a data structure and like any data structure it can be iterated with any type of cycle. msdn has an iterated document about a data collection, by coincidence this collection and a hashtable which is the same as a dictionary. The following la code

Hashtable phones = new Hashtable();
// Alguns adds omitidos por brevidade
phones.Add("Leah", "555-0100");

// Iterar sobre a collecao
System.Console.WriteLine("Name\t\tNumber");
foreach (string name in phones.Keys) 
{
    System.Console.WriteLine(name +"\t"+ phones[name]);
}

There are other ways that correspond to different needs.

Before continuing with these forms it is necessary to realize that a dictionary can be seen as a set of pairs (key, value). This is exactly what you return when you go through the dictionary with an iterator.

  • Iterate over the pairs (key, value) of the dictionary with foreach

foreach (var pair in dicionario)
{
    Console.WriteLine("{0}, {1}", pair.Key, pair.Value);
}
  • Iterate over the pairs (key, value) of the dictionary with LINQ

dicionario.Where(k => k.Key.Contains("ola")).Select(e => new{ ... })
  • Iterate on the values of the dictionary

Any of the above but only in property Values dictionary. This is useful if you are only interested in the values.

  • Iterate over dictionary keys

The same thing that Values, but this time only for the dictionary keys. A property is called Keys

There are other ways to iterate over the dictionary, but these are usually combinations of the forms shown above. For example, consider the following dictionary

var dicionario = new Dictionary<string, int>()
{
    {"1", 2},
    {"1.1", 1},
    {"1.2", 0},
    {"2" -1}
};

It may be interesting to get the values of the dictionary whose key starts with 1:

dicionario.Where(k => k.Key.StartsWith("1"))

Another way to do the same would be:

var chaves1 = dicionario.Keys.Where(k => k.StartsWith("1"));
foreach(var chave in chaves1){
    var valor = dicionario[chave];
    //...
}

The English community also has an equal question.

I usually prefer the first approach. From the point of theoretical view it may also be more efficient, since it has weight O(n * kl) where n and number of dictionary entries and kl and size of the string that Voce is searching for (in my example is 1). The second approach has an operation O(k) the most, where k is the number of keys that match your criteria.

8

One can say that essentially there is only one way. It is repetition through a flow control mechanism, preferably structured. There is no clear pattern, there is common sense and the most obvious tools. The choice of one way or another depends on the circumstance.

The many ways to use are almost circumstantial and tend to infinity.

foreach

The most traditional form we see in most codes written in C# and even in other languages is foreach. The rest are variations of it. The way to use it can vary a lot.

foreach (var par in dicionario) => WriteLine($"{par.Key} => {par.Value}");

Note that each item to be iterated is a key pair and value represented by the type KeyValuePair. Then the var there will catch this guy always.

In this way it goes from the beginning to the end of the dictionary item by item, without any order defined since dictionaries have no order and it returns this pair. You can do whatever you want with it, always accessing the key if you want through the type member Key, or the most common value through the Value.

You could pick up the key or the value:

foreach (var key in dicionario.Keys) => WriteLine($"{key} => {dicionario[key]}");

foreach (var value in dicionario.Values) => WriteLine($"{value}");

I will not go into ways that the dictionary is passed to some method and that returns something manipulated to the foreach cope since this is an indirect way. It has already been noted that there is much variation possible, nor scraped at all with foreach.

for

Not the most appropriate, but you can avoid foreach, that despite being a reasonably concrete form, it has some abstraction built in. Apart from this abstraction, a little, we can have the same result with for. If you do not know what you are doing or have some oversight, it will go wrong. There are two basic ways:

for (var i = 0; i < dicionario.Count; i++) {
    var par = dicionario.ElementAt(i);
    WriteLine($"{par.Key} => {par.Value}");
}

This form can be used when you need a counter next to the dictionary iteration, but it has a problem because the ElementAt() need to scroll through the dictionary. This is probably not what you want.

If you want to access without this problem, use the iterator:

for (var iterador = dicionario.GetEnumerator(); iterador.MoveNext();) {
    var par = iterador.Current;
    WriteLine($"{par.Key} => {par.Value}");
}

I wrote simply, if you do so there will be memory leakage, take this just as an isolated example of demonstration, this code is not suitable for use in production.

There could be a different condition in for and the MoveNext() be at the step site (step, third part of for). Obviously you have other ways of doing the same.

Simply put, that’s the way foreach really operates.

while

The whole for is practically a syntactic sugar for a while. Then the two examples above and several other variations can be realized with this construction as well.

You just have to be careful 'cause if you have one continue within it, in the first case the index will not be evaluated and the increment will not happen in the while, in the for it is guaranteed that it occurs. In the case of iterator there is no problem.

If you want to ensure at least one iteration occurs you can use do...while.

I will not post many variations, only the iterator without memory leak:

using (var iterador = dicionario.GetEnumerator()) {
    while(iterador.MoveNext()) {
        var par = iterador.Current;
        WriteLine($"{par.Key} => {par.Value}");
    }
}

Recursive function

Every loop of repetition can be written as a recursive function, perhaps with adaptations. I don’t think iterating a simple dictionary is a case for a recursive function, unless the value is composed of dictionaries forming a tree. But it is possible to do this. Nor will I try to set an example, I consider it a waste of time, but it is not wrong.

goto

Of course every bond can be expressed more concretely and less structured with goto, but I can’t imagine a reason to do that. Nor will I waste time.

It is a way, although it should not be adequate. But if you think of inadequacy, there are rare cases where the foreach simple is not the most appropriate. Yet people use other ways.

No loop of repetition

I wouldn’t call it iterating. But it is possible to access item by item individually using the index, ElementAt(At) (that there will be an embedded loop), MoveNext() iterator, etc.

Other forms

Save some very creative use (some pretty crazy, but feasible and correct) I can’t imagine other basic building variations. But if you consider small different details there is a huge amount of variation.

I will not speak of cases where it is wrong or at least obsolete to do, let alone give complex solutions that do not add value.

Abstraction.

What can be done is to create abstractions on top of these concrete constructions. You can create a function with a generator. There you can consume these abstractions. One can then consider that each of these abstractions are different ways of iterating over the dictionary. Example:

public static IEnumerable<int> Iterar(Dictionary<string, int> dicionario) {
    foreach (var par in dicionario) yield return par.Value;
}

This can be consumed in many ways. Iteration takes place there, but you use it as the method, you don’t even need to know how it’s done within it. then when using the Iterar() is iterating in a new way.

Imagine you can iterate in infinite ways by doing so. But the basis is the repeat loop that initiates an iteration, moves to the next item and closes when all items are finished or by some specific condition before reaching the end.

LINQ

I was going to make a generic example where you pass one lambda for the method and it performs as iteration body. But that’s exactly what most of the LINQ methods do that we’ll see below. Have a standard method ForEach() is another way, in fact has one in LINQ. It has limitations and is confusing for some. Often it does not do what one expects, semantics is different from normal block usage.

This type of abstraction is so useful that . NET already has many such methods through the LINQ.

There are a huge amount of ready-made methods on . NET to iterate in many ways and there are many others in third-party libraries. And you can make your own extensions. Everything works with enumerable works with dictionary.

There are similar extensions that can be made specifically for dictionaries and that do not work with other enumerable types. Example:

dicionario.Keys.ToList().ForEach(key => WriteLine($"{key} => {dicionario[key]}"));

Recreating the sequence in different order and filtering elements:

dicionario.OrderBy(kv => kv.Key).Where(kv => kv.Value >= 18)

Iterating in parallel:

dicionario.AsParallel().ForAll(par => { WriteLine($"{par.Key} => {par.Value}"); });

Imagine how many examples you could assemble using LINQ.

Other abstractions

It is possible to derive the class Dictionary and make diverse interactions there. It is possible to create an abstraction on top of the enumerator and avoid the pair. Something like this:

public new IEnumerator<T> GetEnumerator() {
   return this.Values.GetEnumerator();
}

You can think of many other ways.

See working in the .NET Fiddle. Also put on the Github for future reference.

Completion

Anyway, you can do a lot of things. There is no finite form of ways to do something so complex, unless you want to reduce to the most concrete case, then just say you need to make a loop sweeping all items, and the most concrete form of all that can be expressed in C# is using the goto to control the repetition.

  • It is important to understand the concept of the enumerator and the key pair and value.

  • If you don’t have a good reason to do it differently, take the foreach picking up pairs, or keys or values. If applicable, pre-filter.

  • If you like abstractions and see advantage in any case, use LINQ.

  • If you will do a specific iteration that you will use in many cases, create a method that does this more concretely and use it where you need it. In the consumption of it for that case could use a more concrete form, but it would be better this method that produces the desired result.

  • I do not agree that the for Elementat is an acceptable way to go through the dictionary. It may be an O(n 2 algorithm)

  • 1

    a forma mais concreta de todas que pode ser expressada em C# é usando o goto para controlar a repetição. Where is there a rule explaining this? Is this really your experience? If you want to mention the goto at least mention the break too

  • @Brunocosta I had forgotten to write about complexity, I made the exception in the answer. As far as I know there is no rule about using the goto, I really don’t even know what you mean by that. It’s not my experience, it’s an obvious fact, if you want to know about the functioning of ties and why the goto is more concrete can ask a question (let me know if you are going to do, I am preparing the answer), does not fit here by size and context. The other forms are nothing more than if and goto. The break has nothing to do with the goto in this context, it is an abstraction of goto.

  • I know how the goto, unlike any other flow mechanism it lets go to any point of execution in the same method... But as you said he usually carries the string code. He also remembers the old Assembly... It was better to answer.

  • You speak in the second example of for that "if you do so there will be memory leakage". That is why Enumerator implement Idisposable?

  • @ramaral in general lines, yes.

  • I was watching the source code, the method Dispose() has an "empty implementation". So it is no problem to use the for that way. Right?

  • @but this is the Dispose() of Dictionary, that neither implements IDisposable, I don’t know why you have it there. The problem is the iterator and not the dictionary.

  • Yes, I’m talking about the iterator. That Dispose() is from Yenumerator returned by getEnumerator(). IEnumerator<T> implements the interface Idisposable

  • @ramaral is true, it does not follow the proper encoding style recommendations :) and confused me. In this case there seems to be no problems, but that’s implementation detail, go that change, can not trust it. The foreach calls the Dispose(). Don’t do it like that bugs hairy if anything changes. That’s why I said that the more concrete you do, the more you have to be aware of the whole mechanism and think about everything that can go wrong.

  • I knew right away that his phrase was due to the implementation, on the part of enumerator, of the interface Idisposable. Yet I saw nothing but a Dictionary had it been necessary to do "Disposis". The source code came to confirm what I thought. I also don’t see that the implementation can change, in this sense.

Show 6 more comments

3

It follows two forms that are quite used:

Dictionary<string, int> d = new Dictionary<string, int>()
    {
        {"cat", 2},
        {"dog", 1},
        {"llama", 0},
        {"iguana", -1}
    };
    // Loop over pairs with foreach.
    foreach (KeyValuePair<string, int> pair in d)
    {
        Console.WriteLine("{0}, {1}", pair.Key, pair.Value);
    }
    // Use var keyword to enumerate dictionary.
    foreach (var pair in d)
    {
        Console.WriteLine("{0}, {1}", pair.Key, pair.Value);
    }
  • 3

    Both are not the same?

  • @jbueno The answer is yes, they are.

  • Yes, it has both the same purpose. I use the latter more because it is simpler.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.