C#

.NET Array Dictionary List String 2D Async DataTable Dates DateTime Enum File For Foreach Format IEnumerable If IndexOf Lambda LINQ Parse Path Process Property Regex Replace Row Sort Split Static StringBuilder Substring Switch Tuple

IndexOf. A string contains many characters. These characters may be searched and tested. We simplify these operations with IndexOf.


This method, a string method, returns the first index of a letter in a string. It can also find a substring. It is often used in looping constructs.

Return: It returns negative one when nothing is found. We must test for -1 if no value may exist.

And: Because -1 is returned in normal situations, we usually need if-statements with IndexOf.


Here, we use IndexOf to see if a string contains a word. We test the string for a substring "dog." We test the result of IndexOf against the special constant -1.

Example: IndexOf returns the location of the string "dog." It is not equal to -1. So the line is written to the console window.

Note: Usually we want to know the exact result of IndexOf. We can store its result in an int local.

Based on: .NET 4.5

C# program that uses IndexOf

using System;

class Program
{
    static void Main()
    {
	// The input string.
	const string value = "Your dog is cute.";

	// Test with IndexOf method.
	if (value.IndexOf("dog") != -1)
	{
	    Console.WriteLine("string contains dog!");
	}
    }
}

Output

string contains dog!

While loop. We often use IndexOf in loops. We have to keep track of several values at once. This prevents us from searching the same parts over and over again.

Here: We loop through the instances of a char in a string. We locate each lowercase a in the string.

While: We call IndexOf within a while-statement. We test it for success each time. If the character is not found, the loop ends.

While

WriteLine: This part is optional. It writes the Substring specified by the index and count arguments.

Console.WriteLine

Tip: We must advance past the current character by adding one to the index. If we do not do this, we will get an infinite loop.

C# program that uses IndexOf in loop

using System;

class Program
{
    static void Main()
    {
	// The input string.
	string s = "I have a cat";

	// Loop through all instances of the letter a.
	int i = 0;
	while ((i = s.IndexOf('a', i)) != -1)
	{
	    // Print out the substring.
	    Console.WriteLine(s.Substring(i));

	    // Increment the index.
	    i++;
	}
    }
}

Output

ave a cat
a cat
at

Return value. This is -1 when IndexOf does not find anything, and the index if it does. Often an IndexOutOfRangeException can provoked by using the -1 in other code (like an array access).

So: Please be careful when using IndexOf. It is probably better to check for negative one at least once in most places.


Substring. We can use IndexOf with the Substring method. Here we get the first substring that begins with a certain pattern or character.

Info: The Substring method returns the rest of the string starting at a specified number.

Substring
C# program that uses Substring

using System;

class Program
{
    static void Main()
    {
	// Input.
	const string s = "I have a cat";

	// Location of the letter c.
	int i = s.IndexOf('c');

	// Remainder of string starting at c.
	string d = s.Substring(i);
	Console.WriteLine(d);
    }
}

Output

cat

Skip start. Often strings have leading characters that we know cannot contain the searched-for value. We can skip these chars. This will give a performance boost—less searching is needed.

C# program that skips start characters

using System;

class Program
{
    static void Main()
    {
	string value = ":100,200";
	// Skip the first character with a startIndex of 1.
	int comma = value.IndexOf(',', 1);
	Console.WriteLine(comma);
    }
}

Output

4

IndexOfAny. This method receives a char array argument. It searches for the first index of any of the characters provided in that array.

IndexOfAny

Note: This method is similar to calling IndexOf several times with the logical OR operator.

However: IndexOfAny has different performance characteristics. It may result in clearer code.


LastIndexOf. This works like IndexOf, but searches in reverse, from the right to the left part of the string. It starts with the last char.

LastIndexOf

Return: LastIndexOf also returns -1 if the argument cannot be located. So it is the same except for search order.

Note: The IndexOf method is actually a FirstIndexOf method. The name just omits the First.


LastIndexOfAny. This one searches in reverse, and tests the character array for any match. It returns the rightmost match possible from the array.

LastIndexOfAny

Contains. This is a wrapper method. It calls IndexOf with StringComparison.Ordinal. It returns true or false, not an integer. So it is a bit simpler to use.

Contains

Internals: If Contains' internal IndexOf returns -1, Contains returns false. Otherwise it returns true.

IndexOf and Contains

IndexOf found result:     index
Contains:                 true 

IndexOf not found result: -1   
Contains:                 false

Between, before and after. Substrings are relative to other parts of their original strings. With IndexOf and LastIndexOf, we can locate relative substrings.

Between, Before, After

IndexOf versus for. Should we prefer IndexOf over for-loops when-possible? Here I test IndexOf() against a single-character iteration for-loop.

Story: I wanted to know if scanning through a string with a single char loop was faster than using IndexOf over each character.

And: I found it is more efficient to scan each character individually than to use IndexOf.

Note: The internal code for IndexOf is more complex. It is harder to optimize for the compiler.

C# program that times for-loop, IndexOf

using System;
using System.Diagnostics;

class Program
{
    const int _max = 1000000;
    static void Main()
    {
	string s = "abc.123.456.xyz";

	// Version 1: use for-loop to count chars.
	var s1 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    int c = 0;
	    for (int e = 0; e < s.Length; e++)
	    {
		if (s[e] == '.')
		{
		    c++;
		}
	    }
	}
	s1.Stop();

	// Version 2: use IndexOf to count chars.
	var s2 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    int c = 0;
	    int e = 0;
	    while ((e = s.IndexOf('.', e)) != -1)
	    {
		e++;
		c++;
	    }
	}
	s2.Stop();

	// Result times.
	Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /
	    _max).ToString("0.00 ns"));
	Console.Read();
    }
}

Results

18.21 ns:    For-loop
26.78 ns:    IndexOf, while-loop

For-loop. We can replace character iteration loops with IndexOf in some situations. This can result in much clearer code, but there will be some performance impact. IndexOf may be clearer.

Note: I executed these two pieces of code and tested their performance in tight loops.

Result: The imperative for-loop was faster by a couple nanoseconds. If you are desperate for performance, this can help.

For-loop version

int number = -1;
for (int y = 0; y < value.Length; y++)
{
    if (value[y] == '1')
    {
	number = y;
	break;
    }
}

IndexOf version

int number = value.IndexOf('1');

String versus char. Is there is a difference between calling IndexOf with a single character string argument, and with a char argument? I tested this.

Result: The string IndexOf will require more CPU cycles. And even if we pass in StringComparison.Ordinal, it is slower.

So: The IndexOf form that uses a char argument is more efficient. Using a string is many times slower than using a char value.

C# program that times IndexOf, char versus string

using System;
using System.Diagnostics;

class Program
{
    const int _max = 1000000;
    static void Main()
    {
	string value = "The puppy is adorable.";

	// Version 1: use char argument.
	var s1 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    int result = value.IndexOf('a');
	}
	s1.Stop();

	// Version 2: use string argument.
	var s2 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    int result = value.IndexOf("a");
	}
	s2.Stop();

	// Result times.
	Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /
	    _max).ToString("0.00 ns"));
	Console.Read();
    }
}

Results

 13.07 ns:    IndexOf char argument
226.86 ns:    IndexOf string argument

Other IndexOf methods. We call IndexOf on strings, but we can also use (different) IndexOf methods on arrays and Lists. These also return -1 if nothing is found.

Array.IndexOfArray.LastIndexOfList: IndexOf

Powerful. We commonly use IndexOf to search for chars (or substrings) in strings. For complex problems, a for-loop may be easier to write and faster to execute.


A search method. There is no built-in string method called Search. But the general idea is performed by IndexOf, IndexOfAny, LastIndexOf and LastIndexOfAny.