The following 3 example codes are identical except for tiny differences, which is commented by Look at here. However the speed differs much.
Sample 1: It runs 59 sec in my computer.
namespace AoDtest
{
class Program
{
static bool IsWin(IList<string[]> slotView)
{
string[] symbol = new string[3];
for (int reelID = 0; reelID < 3; reelID++)
{
symbol[reelID] = slotView[reelID][1];
}
if (symbol.Contains("B")) return true; // Look at here
// if (symbol.Any(x => x == "B")) return true;
return false;
}
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int count = 0;
string reel1 = "J K 10 S R 10 K Q 10 A Q K 10 Q K R 10 K R 10 J R 10 A Q R A 10 J Q 10 R K 10 L S A L 10 Q A S Q A R 10 K R L 10 R A S 10 L Q A L 10 S R 10 Q";
string reel2 = "L K J B A 10 Q L R Q J L Q R J Q 10 J R L Q J 10 B Q K 10 L Q J S Q 10 L A Q L J R Q 10 S A 10 Q B J A L S K Q S J 10 Q L S Q L K 10 R";
string reel3 = "J S A J B Q K J S 2x R Q S J R L J S K L J K L S J 10 B K Q S J K L A K J A K S 10 J A R 2x L K J A B K J R K J A K J A L R J K R";
string[] myreel1 = reel1.Split('\t');
string[] myreel2 = reel2.Split('\t');
string[] myreel3 = reel3.Split('\t');
for (int n = 0; n < 200; n++)
{
for (int i = 0; i < myreel1.Length; i++)
for (int j = 0; j < myreel2.Length; j++)
for (int k = 0; k < myreel3.Length; k++)
{
string[][] slotView = new string[3][];
for (int m = 0; m < 3; m++)
{
slotView[m] = new string[2];
}
slotView[0][1] = myreel1[i];
slotView[1][1] = myreel2[j];
slotView[2][1] = myreel3[k];
if (IsWin(slotView)) count++;
}
}
watch.Stop();
Console.WriteLine(count);
Console.WriteLine((double)reel1.Length * reel2.Length * reel3.Length / count);
Console.WriteLine(watch.Elapsed);
}
}
}
Sample 2: It runes 20 sec in my computer.
namespace AoDtest
{
class Program
{
static bool IsWin(IList<string[]> slotView)
{
string[] symbol = new string[3];
for (int reelID = 0; reelID < 3; reelID++)
{
symbol[reelID] = slotView[reelID][1];
}
// if (symbol.Contains("B")) return true;
if (symbol.Any(x => x == "B")) return true; // Look at here
return false;
}
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int count = 0;
string reel1 = "J K 10 S R 10 K Q 10 A Q K 10 Q K R 10 K R 10 J R 10 A Q R A 10 J Q 10 R K 10 L S A L 10 Q A S Q A R 10 K R L 10 R A S 10 L Q A L 10 S R 10 Q";
string reel2 = "L K J B A 10 Q L R Q J L Q R J Q 10 J R L Q J 10 B Q K 10 L Q J S Q 10 L A Q L J R Q 10 S A 10 Q B J A L S K Q S J 10 Q L S Q L K 10 R";
string reel3 = "J S A J B Q K J S 2x R Q S J R L J S K L J K L S J 10 B K Q S J K L A K J A K S 10 J A R 2x L K J A B K J R K J A K J A L R J K R";
string[] myreel1 = reel1.Split('\t');
string[] myreel2 = reel2.Split('\t');
string[] myreel3 = reel3.Split('\t');
for (int n = 0; n < 200; n++)
{
for (int i = 0; i < myreel1.Length; i++)
for (int j = 0; j < myreel2.Length; j++)
for (int k = 0; k < myreel3.Length; k++)
{
string[][] slotView = new string[3][];
for (int m = 0; m < 3; m++)
{
slotView[m] = new string[2];
}
slotView[0][1] = myreel1[i];
slotView[1][1] = myreel2[j];
slotView[2][1] = myreel3[k];
if (IsWin(slotView)) count++;
}
}
watch.Stop();
Console.WriteLine(count);
Console.WriteLine((double)reel1.Length * reel2.Length * reel3.Length / count);
Console.WriteLine(watch.Elapsed);
}
}
}
Sample 3: Now I use Contains() again, but move some code from IsWin into Main, It runs 14 sec now, why it is faster here?
Big Discovery: IList<string> symbol if I switch to string[] symbol then it runs 57 secs.
namespace AoDtest
{
class Program
{
static bool IsWin(IList<string> symbol)
{
if (symbol.Contains("B")) return true;
// if (symbol.Any(x => x == "B")) return true;
return false;
}
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int count = 0;
string reel1 = "J K 10 S R 10 K Q 10 A Q K 10 Q K R 10 K R 10 J R 10 A Q R A 10 J Q 10 R K 10 L S A L 10 Q A S Q A R 10 K R L 10 R A S 10 L Q A L 10 S R 10 Q";
string reel2 = "L K J B A 10 Q L R Q J L Q R J Q 10 J R L Q J 10 B Q K 10 L Q J S Q 10 L A Q L J R Q 10 S A 10 Q B J A L S K Q S J 10 Q L S Q L K 10 R";
string reel3 = "J S A J B Q K J S 2x R Q S J R L J S K L J K L S J 10 B K Q S J K L A K J A K S 10 J A R 2x L K J A B K J R K J A K J A L R J K R";
string[] myreel1 = reel1.Split('\t');
string[] myreel2 = reel2.Split('\t');
string[] myreel3 = reel3.Split('\t');
for (int n = 0; n < 200; n++)
{
for (int i = 0; i < myreel1.Length; i++)
for (int j = 0; j < myreel2.Length; j++)
for (int k = 0; k < myreel3.Length; k++)
{
string[][] slotView = new string[3][];
for (int m = 0; m < 3; m++)
{
slotView[m] = new string[2];
}
slotView[0][1] = myreel1[i];
slotView[1][1] = myreel2[j];
slotView[2][1] = myreel3[k];
string[] symbol = new string[3];
for (int reelID = 0; reelID < 3; reelID++)
{
symbol[reelID] = slotView[reelID][1]; // Look at here
}
if (IsWin(symbol))
{
count++;
}
}
}
watch.Stop();
Console.WriteLine(count);
Console.WriteLine((double)reel1.Length * reel2.Length * reel3.Length / count);
Console.WriteLine(watch.Elapsed);
}
}
}
Sample 4: Similar to Sample 3, but use Any instead, runs 17 sec.
Big Discovery: IList<string> symbol if I switch to string[] symbol then it runs 18 secs.
namespace AoDtest
{
class Program
{
static bool IsWin(IList<string> symbol)
{
if (symbol.Contains("B")) return true;
// if (symbol.Any(x => x == "B")) return true;
return false;
}
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int count = 0;
string reel1 = "J K 10 S R 10 K Q 10 A Q K 10 Q K R 10 K R 10 J R 10 A Q R A 10 J Q 10 R K 10 L S A L 10 Q A S Q A R 10 K R L 10 R A S 10 L Q A L 10 S R 10 Q";
string reel2 = "L K J B A 10 Q L R Q J L Q R J Q 10 J R L Q J 10 B Q K 10 L Q J S Q 10 L A Q L J R Q 10 S A 10 Q B J A L S K Q S J 10 Q L S Q L K 10 R";
string reel3 = "J S A J B Q K J S 2x R Q S J R L J S K L J K L S J 10 B K Q S J K L A K J A K S 10 J A R 2x L K J A B K J R K J A K J A L R J K R";
string[] myreel1 = reel1.Split('\t');
string[] myreel2 = reel2.Split('\t');
string[] myreel3 = reel3.Split('\t');
for (int n = 0; n < 200; n++)
{
for (int i = 0; i < myreel1.Length; i++)
for (int j = 0; j < myreel2.Length; j++)
for (int k = 0; k < myreel3.Length; k++)
{
string[][] slotView = new string[3][];
for (int m = 0; m < 3; m++)
{
slotView[m] = new string[2];
}
slotView[0][1] = myreel1[i];
slotView[1][1] = myreel2[j];
slotView[2][1] = myreel3[k];
string[] symbol = new string[3];
for (int reelID = 0; reelID < 3; reelID++)
{
symbol[reelID] = slotView[reelID][1]; // Look at here
}
if (IsWin(symbol))
{
count++;
}
}
}
watch.Stop();
Console.WriteLine(count);
Console.WriteLine((double)reel1.Length * reel2.Length * reel3.Length / count);
Console.WriteLine(watch.Elapsed);
}
}
}
This is rather interesting.
Documentation for
IEnumerable<T>.Containssays that if the source parameter implementsICollection<T>, then it callsICollection<T>.Contains. And sincestring[]implementsICollection<string>, that’s what gets called.The
Arrayimplementation ofICollection<T>.Containsends up callingArray.IndexOf.If you change your code to read:
It executes as fast as
Any. Same if you change the code to:In my tests, calling
Array.IndexOfis twice as fast as callingsymbol.Contains.I suspect what’s slowing things down is that
IEnumerable<T>.Containshas to decide with each call whether it will callICollection<T>.Contains, or do something else. That decision doesn’t have to be made whenAnyis called.You can replace all the code in
IsWinwith this, which is faster still than either of the above, and is a whole lot simpler.Then, of course, you can just get rid of the
IsWinmethod altogether and write in your inner loop: