0

I need to get the first letter in a string, and was trying to use stringValue[0]. This gave compilation error when I tried to pass it as a parameter to a method, because the method only took string as type for that parameter. So I have several options to convert it to string:

myMethod(stringValue[0].ToString());
myMethod(new String(stringValue[0], 1));
myMethod(stringValue.Substring(0,1));
myMethod("" + stringValue[0]);

Which method is the best and fastest regarding performance (thoughts on best practice is also welcome)?

awe
  • 21,938
  • 6
  • 78
  • 91

3 Answers3

2

Use String.Substring:

string firstChar = stringValue.Substring(0, 1);

According to the performance part of your question.

I wouldn't take performance into consideration here unless it was actually becoming a problem for you - in which case the only way you'd know would be to have test cases, and then it's easy to just run those test cases for each option and compare the results. I'd expect Substring to probably be the fastest here, simply because Substring always ends up creating a string from a single chunk of the original input, whereas Remove has to at least potentially glue together a start chunk and an end chunk.

Fastest way to remove first char in a string

However, if you want to micro-optimize and you really need just the first character, it seems that the string indexer + constructor is a little bit faster than others:

string stringValue = "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest";
var sw = new System.Diagnostics.Stopwatch();
string firstChar;
sw.Start();
for(int i=0; i<100000000; i++)
    firstChar = stringValue.Substring(0, 1);
sw.Stop();
Console.WriteLine("Substring Elapsed: " + sw.Elapsed);

sw.Restart();
for (int i = 0; i < 100000000; i++)
    firstChar = stringValue[0].ToString();
sw.Stop();
Console.WriteLine("Char[]-Indexer-ToString Elapsed: " + sw.Elapsed);

sw.Restart();
for (int i = 0; i < 100000000; i++)
    firstChar = new string(stringValue[0],1);
sw.Stop();
Console.WriteLine("Char[]-Indexer-Constructor Elapsed: " + sw.Elapsed);

Result:

Substring Elapsed: 00:00:03.0214131
Char[]-Indexer-ToString Elapsed: 00:00:02.1274226
Char[]-Indexer-Constructor Elapsed: 00:00:01.7042839

But note that this is really micro-optimization. Readability is more important in most cases. Consider also that you might need to take the first two characters sometime which is easy with String.Substring, an array indexer cannot return multiple characters.

Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • 3
    Hey Tim, I think it would be better with an explanation why this gets better performance than others. `;)` – Soner Gönül Nov 26 '13 at 12:05
  • @SonerGönül: Yes, sorry, i noticed too late that he actually wants to know the fastest approach and didn't have the time to add an explanation. But now i have added an answer on a similar question. – Tim Schmelter Nov 26 '13 at 12:13
  • 2
    "I'd _expect_ Substring to _probably_ be the fastest here" - seems legit. – Gusdor Nov 26 '13 at 12:13
  • 1
    @TimSchmelter If Jon says `SubString` is the fastest, who will argue with it? `:)` +1 from mine. – Soner Gönül Nov 26 '13 at 12:15
  • @poke There are valuable points at stake here! Serious business. – Gusdor Nov 26 '13 at 12:32
2

Proposed Solution

string input = "This is a string";
string firstChar = new String(input[0], 1);

This is the least number of operations you can do.

  1. extract the first char by index
  2. pass the char to the constructor of String

String Constructor (Char, Int32)

Performance Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StringPerf
{
    class Program
    {
        static string firstChar;

        static void Main(string[] args)
        {
            string input = "This is a sample string";
            int count = 100000;
            RunPerf("Warmup", 1, () =>
                {
                    PerfContructor(input);
                    PerfSubstring(input);
                    PerfAppend(input);
                });

            Console.WriteLine();
            Console.WriteLine();

            RunPerf("Constructor", count, () => PerfContructor(input));
            Console.WriteLine();

            RunPerf("ToString", count, () => PerfToString(input));
            Console.WriteLine();

            RunPerf("Substring", count, () => PerfSubstring(input));
            Console.WriteLine();

            RunPerf("Append", count, () => PerfAppend(input));

            Console.ReadLine();
        }

        static void PerfContructor(string input)
        {
            firstChar = new String(input[0], 1);
        }

        static void PerfToString(string input)
        {
            firstChar = input[0].ToString();
        }

        static void PerfSubstring(string input)
        {
            firstChar = input.Substring(0, 1);
        }

        static void PerfAppend(string input)
        {
            firstChar = "" + input[0];
        }

        static void RunPerf(string name, int count, Action action)
        {
            var sw = new System.Diagnostics.Stopwatch();
            Console.WriteLine(string.Format("Starting perf for {0}. {1} times", name, count));

            sw.Start();
            for (int i = 0; i < count; i++)
            {
                action();
            }
            sw.Stop();
            Console.WriteLine(string.Format("{0} completed in {1}", name, sw.Elapsed));
        }
    }
}

Results

Starting perf for Warmup. 1 times
Warmup completed in 00:00:00.0003153


Starting perf for Constructor. 9999999 times
Constructor completed in 00:00:00.1961569

Starting perf for ToString. 9999999 times
ToString completed in 00:00:00.2890530

Starting perf for Substring. 9999999 times
Substring completed in 00:00:00.2412256

Starting perf for Append. 9999999 times
Append completed in 00:00:00.3271857
Gusdor
  • 14,001
  • 2
  • 52
  • 64
0

Based on the answers by Tim Schmelter and Gusdor I did some testing on my own, and the results made it clear that the fastest methods were

stringValue[0].ToString()

and

new String(stringValue[0], 1)

Which of the two is fastest is unclear, as my tests were inconclusive regarding those two. I tried to run them in different order, and it varied which one was the fastest.

I ran it 2E9 times, and these two fastest methods took about 30 seconds.
In comparison, the Substring method was 43 seconds, and the append method was 50 seconds.

Community
  • 1
  • 1
awe
  • 21,938
  • 6
  • 78
  • 91
  • I found that the two methods varied in speed as i increased the test iteration count. I fixed this by assigning to a `static` `string` on each test. I think allocation time was polluting the results. – Gusdor Nov 27 '13 at 08:10