foreach loops are really convenient, but are for loops faster? It’s a simple question, but one that has really wide implications in almost any codebase. Today’s article tests them out to see which is faster for looping over arrays and Lists. Read on to see which is quicker!

Today’s test is simple. It makes an array of object and a System.Collections.Generic.List of object, each with a given length and then loops over them using for and foreach loops. Since this takes less than a millisecond, it runs each loop 100,000 times to get a useful result. Here’s the test script:

using System;
using System.Collections.Generic;
 
using UnityEngine;
 
public class TestScript : MonoBehaviour
{
	private const int NumIterations = 100000;
 
	private string report;
 
	void Start()
	{
		report = "Size,Array For Time,Array Foreach Time,List For Time,List Foreach Time\n";
		var sizes = new []{10,100,1000};
		foreach (var size in sizes)
		{
			report += Test(size);
		}
	}
 
	private string Test(int size)
	{
		var array = new object[size];
		var list = new List<object>(size);
		list.AddRange(array);
		var stopwatch = new System.Diagnostics.Stopwatch();
		object obj = null;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var iteration = 0; iteration < NumIterations; ++iteration)
		{
			for (int i = 0, len = array.Length; i < len; ++i)
			{
				obj = array[i];
			}
		}
		var arrayForTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var iteration = 0; iteration < NumIterations; ++iteration)
		{
			foreach (var cur in array)
			{
			}
		}
		var arrayForeachTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var iteration = 0; iteration < NumIterations; ++iteration)
		{
			for (int i = 0, len = list.Count; i < len; ++i)
			{
				obj = list[i];
			}
		}
		var listForTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var iteration = 0; iteration < NumIterations; ++iteration)
		{
			foreach (var cur in list)
			{
			}
		}
		var listForeachTime = stopwatch.ElapsedMilliseconds;
 
		return size + ","
			+ arrayForTime + ","
			+ arrayForeachTime + ","
			+ listForTime + ","
			+ listForeachTime + "\n";
	}
 
	void OnGUI()
	{
		GUI.TextArea(new Rect(0, 0, Screen.width, Screen.height), report);
	}
}

If you want to try out the test yourself, simply paste the above code into a TestScript.cs file in your Unity project’s Assets directory and attach it to the main camera game object in a new, empty project. Then build in non-development mode for 64-bit processors and run it windowed at 640×480 with fastest graphics. I ran it that way on this machine:

  • 2.3 Ghz Intel Core i7-3615QM
  • Mac OS X 10.10.4
  • Unity 5.1.2f1, Mac OS X Standalone, x86_64, non-development
  • 640×480, Fastest, Windowed

And here are the results I got:

Size Array For Time Array Foreach Time List For Time List Foreach Time
10 2 1 3 19
100 28 10 35 95
1000 243 75 343 832

For vs. Foreach (Array of 10)

For vs. Foreach (Array of 100)

For vs. Foreach (Array of 1000)

For vs. Foreach (List of 10)

For vs. Foreach (List of 100)

For vs. Foreach (List of 1000)

The results for arrays are clearly in favor of foreach as the faster loop by a margin of 2-3x. List, on the other hand, favors the for loop by 2-6x.

These are some really wide performance gaps that you should pay attention to if you are looping over some really long arrays or lists. However, keep in mind that the above loops were run 100,000 times so the actual times are much smaller. The worst time—a List of 1,000 with foreach—only took an average of 0.00832 milliseconds which is really small. A list of a million elements would presumably take 8 milliseconds and in that case you’d get a really nice optimization by switching to a for loop. To do even better, consider an unsafe code loop.

In conclusion, there are two takeaways for this test. First, one of the types of loop is much faster than the other and it depends on what you’re looping over. Second, looping is so fast in both cases that the performance difference probably doesn’t matter in your app. If you’ve seen any evidence to the contrary or have any best practices you follow for your own looping, please share in the comments!