Home
C#
for String Loop, Count Spaces
Updated Sep 12, 2023
Dot Net Perls
String for-loop. The "for" keyword can loop over characters in strings. But some code examples use an inefficient pattern. This causes unnecessary allocations on the managed heap.
An optimization. By directly accessing characters, not strings, loops can be improved and simplified. Many programs can be improved.
for
Requirements. Consider a string like "Dot Net Perls website" with spaces between words. We want to loop over each the string, in an efficient way, counting spaces.
Input = Dot Net Perls website Spaces = 3
First example. To begin, we see the optimal looping code. We use a for-loop to iterate over a string, and we do not incur any excess allocations.
using System; class Program { public static void Main() { string input = "Dot Net Perls website"; int spaces = 0; for (int i = 0; i < input.Length; i++) { if (input[i] == ' ') { spaces++; } } Console.WriteLine("SPACES: " + spaces); } }
SPACES: 3
Benchmark. Here we consider 2 loops over a string literal's character data. Each loop compares each character in the source string against the space character.
Here We count spaces in the string with 2 loops. The first version is much faster—it should always be used.
Version 1 The first loop checks each char directly. No allocations on the managed heap occur—this is a fast loop.
Version 2 The second loop in the program also uses a for-loop. It calls the ToString method.
ToString
Result It is much faster to avoid calling ToString to test the characters in a string. Tested with .NET 5 on Linux.
using System; using System.Diagnostics; class Program { static int A(string input) { int spaces = 0; for (int i = 0; i < input.Length; i++) { if (input[i] == ' ') { spaces++; } } return spaces; } static int B(string input) { int spaces = 0; for (int i = 0; i < input.Length; i++) { if (input[i].ToString() == " ") { spaces++; } } return spaces; } const int _max = 1000000; static void Main() { var s1 = Stopwatch.StartNew(); // Version 1: use direct char for-loop. for (int i = 0; i < _max; i++) { if (A("Dot Net Perls website") == 0) { return; } } s1.Stop(); var s2 = Stopwatch.StartNew(); // Version 2: use ToString in for-loop. for (int i = 0; i < _max; i++) { if (B("Dot Net Perls website") == 0) { return; } } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } }
24.32 ns A 264.23 ns B (ToString)
Result note. Let us consider the results. The for-loop that uses direct character comparisons is far faster than the for-loop that invokes the ToString method.
Benchmark
Another note. The ToString loop here is similar to code that loops over a string by taking a one-character substring. This results in a string allocation.
Note If you are testing characters, you also do not need to do this. Loops that use Substring will be much slower.
String Substring
A summary. Chars should be directly tested in string loops. Developers who are accustomed to other languages (like Java) sometimes make looping mistakes.
Dot Net Perls is a collection of pages with code examples, which are updated to stay current. Programming is an art, and it can be learned from examples.
Donate to this site to help offset the costs of running the server. Sites like this will cease to exist if there is no financial support for them.
Sam Allen is passionate about computer languages, and he maintains 100% of the material available on this website. He hopes it makes the world a nicer place.
This page was last updated on Sep 12, 2023 (edit).
Home
Changes
© 2007-2025 Sam Allen