Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use each type of loop?

Tags:

c#

loops

I'm learning the basics of programming here (C#) but I think this question is generic in its nature.

What are some simple practical situations that lend themselves closer to a particular type of loop?

The while and for loops seem pretty similar and there are several SO questions addressing the differences between the two. How about foreach? From my basic understanding, its seems I ought to be able to do everything a foreach loop does within a for loop.

like image 792
super9 Avatar asked Dec 03 '22 03:12

super9


2 Answers

Which ever works best for code readability. In other words use the one that fits the situation best.

while: When you have a condition that needs to be checked at the start of each loop. e.g. while(!file.EndOfFile) { }

for: When you have an index or counter you are incrementing on each loop. for (int i = 0; i<array.Length; i++) { }. Essentially, the thing you are looping over is an indexable collection, array, list, etc.

foreach: When you are looping over a collection of objects or other Enumerable. In this event you may not know (or care) the size of the collection, or the collection is not index based (e.g. a set of objects). Generally I find foreach loops to be the most readable when I'm not interested in the index of something or any other exit conditions.

Those are my general rules of thumb anyway.

like image 138
Colin Mackay Avatar answered Dec 04 '22 17:12

Colin Mackay


1. foreach and for

A foreach loop works with IEnumerator, when a for loop works with an index (in object myObject = myListOfObjects[i], i is the index).

There is a big difference between the two:

  • an index can access directly any object based on its position within a list.

  • an enumerator can only access the first element of a list, and then move to the next element (as described in the previous link from the msdn). It cannot access an element directly, just knowing the index of the element within a list.

So an enumerator may seem less powerful, but:

  • you don't always know the position of elements in a group, because all groups are not ordered/indexed.
  • you don't always know the number of elements in a list (think about a linked list).
  • even when it's ordered, the indexed access of a list may be based internally on an enumerator, which means that each time you're accessing an element by its position you may be actually enumerating all elements of the list up until the element you want.
  • indexes are not always numeric. Think about Dictionary.

So actually the big strength of the foreach loop and the underlying use of IEnumerator is that it applies to any type which implements IEnumerable (implementing IEnumerable just means that you provide a method that returns an enumerator). Lists, Arrays, Dictionaries, and all other group types all implement IEnumerable. And you can be sure that the enumerator they have is as good as it gets: you won't find a fastest way to go through a list.

So, the for loop can generally be considered as a specialized foreach loop:

public void GoThrough(List<object> myList)
{
    for (int i=0; i<myList.Count; i++)
    {
        MessageBox.Show(myList[i].ToString());
    }
}

is perfectly equivalent to:

public void GoThrough(List<object> myList)
{
    foreach (object item in myList)
    {
        MessageBox.Show(item.ToString());
    }
}

I said generally because there is an obvious case when the for loop is necessary: when you need the index (i.e. the position in the list) of the object, for some reason (like displaying it). You will though eventually realize that this happens only in specific cases when you do good .NET programming, and that foreach should be your default candidate for loops over a group of elements.

Now to keep comparing the foreach loop, it is indeed just an eye-candy specific while loop:

public void GoThrough(IEnumerable myEnumerable)
{
    foreach (object obj in myEnumerable)
    {
        MessageBox.Show(obj.ToString());
    }
}

is perfectly equivalent to:

public void GoThrough(IEnumerable myEnumerable)
{
    IEnumerator myEnumerator = myEnumerable.GetEnumerator();
    while (myEnumerator.MoveNext())
    {
        MessageBox.Show(myEnumerator.Current.ToString());
    }
}

The first writing is a lot simpler though.

2. while and do..while

The while (condition) {action} loop and the do {action} while (condition) loop just differ from each other by the fact that the first one tests the condition before applying the action, when the second one applies the action, then tests the condition. The do {..} while (..) loop is used quite marginally compared to the others, since it runs the action at least once even if the condition is initially not met (which can lead to trouble, since the action is generally dependent on the condition).

The while loop is more general than the for and foreach ones, which apply specifically to lists of objects. The while loop just has a condition to go on, which can be based on anything. For example:

string name = string.empty;
while (name == string.empty)
{
    Console.WriteLine("Enter your name");
    name = Console.ReadLine();
}

asks the user to input his name then press Enter, until he actually inputs something. Nothing to do with lists, as you can see.

3. Conclusion

When you are going through a list, you should use foreach unless you need the numeric index, in which case you should use for. When it doesn't have anything to do with list, and it's just a procedural construction, you should use while(..) {..}.

Now to conclude with something less restrictive: your first goal with .NET should be to make your code readable/maintainable and make it run fast, in that order of priority. Anything that achieves that is good for you. Personally though, I think the foreach loop has the advantage that potentially, it's the most readable and the fastest.

Edit: there is an other case where the for loop is useful: when you need indexing to go through a list in a special way or if you need to modify the list when in the loop. For example, in this case because we want to remove every null element from myList:

for (int i=myList.Count-1; i>=0; i--)
{
    if (myList[i] == null) myList.RemoveAt(i);
}

You need the for loop here because myList cannot be modified from within a foreach loop, and we need to go through it backwards because if you remove the element at the position i, the position of all elements with an index >i will change.

But the use for these special constructions have been reduced since LINQ. The last example can be written like this in LINQ for example:

myList.RemoveAll(obj => obj == null);

LINQ is a second step though, learn the loops first.

like image 31
Evren Kuzucuoglu Avatar answered Dec 04 '22 17:12

Evren Kuzucuoglu