Last active
December 18, 2015 21:48
-
-
Save anderssonjohan/5849718 to your computer and use it in GitHub Desktop.
Which method is the fastest one of string StartsWith, Substring and IndexOf? (Spoiler: Substring)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
using System.Threading.Tasks; | |
namespace startswithorsubstring | |
{ | |
class Program | |
{ | |
const string wsHref = "workspace://oeuoooououoeuouoeuoeu/12312321831283283182328"; | |
const string noWsHref = "cases/12123132"; | |
static Regex regex = new Regex( "workspace://(?<Type>.*)/(?<Name>[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}).*", RegexOptions.Compiled ); | |
public static bool IsWorkspaceUri( string uri ) | |
{ | |
if ( String.IsNullOrEmpty( uri ) ) | |
return false; | |
Match m = regex.Match( uri ); | |
return m.Success; | |
} | |
static readonly Expression<Func<string, bool>> startsWithEx = s => s.StartsWith( "workspace:" ); | |
static readonly Expression<Func<string, bool>> substringEx = s => s.Length > 10 && s.Substring( 0, 10 ) == "workspace:"; | |
static readonly Expression<Func<string, bool>> indexOfEx = s => s.IndexOf( "workspace:", 0 ) != -1; | |
static readonly Func<string, bool> startsWith = startsWithEx.Compile(); | |
static readonly Func<string, bool> substring = substringEx.Compile(); | |
static readonly Func<string, bool> indexOf = indexOfEx.Compile(); | |
static void Main( string[] args ) | |
{ | |
Console.WriteLine( "ws href: {0} no ws href: {1}", wsHref, noWsHref ); | |
Console.WriteLine( "startswith: {0}", startsWithEx ); | |
Console.WriteLine( "substring: {0}", substringEx ); | |
Console.WriteLine( "indexOf: {0}", indexOfEx ); | |
int rounds; | |
if ( !( args.Length == 1 && Int32.TryParse( args[0], out rounds ) ) ) | |
{ | |
rounds = 3; | |
} | |
foreach ( var round in Enumerable.Range( 1, rounds ) ) | |
{ | |
Console.WriteLine( "Round {0}", round ); | |
RunTest(); | |
} | |
Console.ReadLine(); | |
} | |
static void RunTest() | |
{ | |
var wsStartsWith = ElapsedMs( wsHref, startsWith ); | |
var wsSubstring = ElapsedMs( wsHref, substring ); | |
var wsIndexOf = ElapsedMs( wsHref, indexOf ); | |
var wsRx = ElapsedMs( wsHref, IsWorkspaceUri ); | |
var noWsStartsWith = ElapsedMs( noWsHref, startsWith ); | |
var noWsSubstring = ElapsedMs( noWsHref, substring ); | |
var noWsIndexOf = ElapsedMs( noWsHref, indexOf ); | |
var noWsRx = ElapsedMs( wsHref, IsWorkspaceUri ); | |
Console.WriteLine(); | |
Console.WriteLine( "ws uri" ); | |
Console.WriteLine(); | |
Console.WriteLine("startswith: {0}", wsStartsWith ); | |
Console.WriteLine("substring: {0}", wsSubstring ); | |
Console.WriteLine("indexof: {0}", wsIndexOf ); | |
Console.WriteLine("rx: {0}", wsRx ); | |
Console.WriteLine(); | |
Console.WriteLine( "no ws uri" ); | |
Console.WriteLine(); | |
Console.WriteLine( "startswith: {0}", noWsStartsWith ); | |
Console.WriteLine( "substring: {0}", noWsSubstring ); | |
Console.WriteLine( "indexof: {0}", noWsIndexOf ); | |
Console.WriteLine( "rx: {0}", noWsRx ); | |
Console.WriteLine( "=====" ); | |
} | |
static double ElapsedMs( string wsHref, Func<string,bool> action ) | |
{ | |
var times = new List<Stopwatch>(); | |
var pelle = 0; | |
for ( var i = 0; i < 10; i++ ) | |
{ | |
var sw1 = Stopwatch.StartNew(); | |
for ( var j = 0; j < 1000000; j++ ) | |
{ | |
if ( action( wsHref ) ) | |
{ | |
// yay | |
pelle++; | |
} | |
} | |
sw1.Stop(); | |
times.Add( sw1 ); | |
} | |
return times.Average( sw => sw.ElapsedMilliseconds ); | |
} | |
} | |
} |
Added test for existing code being used - using a regex:
ws href: workspace://oeuoooououoeuouoeuoeu/12312321831283283182328 no ws href: cases/12123132
startswith: s => s.StartsWith("workspace:")
substring: s => ((s.Length > 10) AndAlso (s.Substring(0, 10) == "workspace:"))
indexOf: s => (s.IndexOf("workspace:", 0) != -1)
Round 1
ws uri
startswith: 546,9
substring: 45,3
indexof: 567,9
rx: 2970
no ws uri
startswith: 260,2
substring: 39,6
indexof: 1225,8
rx: 2904,3
=====
Round 2
ws uri
startswith: 533,5
substring: 44,6
indexof: 557
rx: 2952,8
no ws uri
startswith: 265,1
substring: 42,1
indexof: 1221,5
rx: 2939,6
=====
Round 3
ws uri
startswith: 532,2
substring: 45,7
indexof: 554,5
rx: 2938,6
no ws uri
startswith: 259,2
substring: 39,9
indexof: 1245,5
rx: 3016,9
=====
Fun fact: non-compiled regex takes about 5500ms.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sample output: