using System.Collections.Generic;
using System.Text.RegularExpressions;
public static void Main()
string str1 = "021A,775U,000A,021A,1U2,206B,240,249,255B,260,263B,280,294,2U1,306B,336B,345,427,440,442,474,477,4U4,500508,523,543L,580,584,772,802,P55,VB" ;
string str2 = "772+240+802+P55+263B+1U2+VB";
Console.WriteLine("Simple Testing");
Console.WriteLine("Expect True:" + ContainsAll(str1, str2));
string str3 = "772+240+802+P55+263B+508+VB";
Console.WriteLine("Expect False:" + ContainsAll(str1, str3));
StringContainsAllTests tests = new StringContainsAllTests();
Console.WriteLine("LinqExcept (true): " + tests.LinqExcept(str1, str2));
Console.WriteLine("RegexMatchIterator (true): " + tests.RegexMatchIterator(str1, str2));
Console.WriteLine("RegexMatchAllPattern (true): " + tests.RegexMatchAllPattern(str1, str2));
Console.WriteLine("LinqExcept (false): " + tests.LinqExcept(str1, str3));
Console.WriteLine("RegexMatchIterator (false): " + tests.RegexMatchIterator(str1, str3));
Console.WriteLine("RegexMatchAllPattern (false): " + tests.RegexMatchAllPattern(str1, str3));
Console.WriteLine("Testing boundary conditions, all should match");
Console.WriteLine("ConcatenatedString: " + tests.ConcatenatedString(str1, "021A"));
Console.WriteLine("ConcatenatedString: " + tests.ConcatenatedString(str1, "021A+VB"));
Console.WriteLine("ConcatenatedString: " + tests.ConcatenatedString(str1, "VB"));
Console.WriteLine("RegexMatchIterator: " + tests.RegexMatchIterator(str1, "021A"));
Console.WriteLine("RegexMatchIterator: " + tests.RegexMatchIterator(str1, "021A+VB"));
Console.WriteLine("RegexMatchIterator: " + tests.RegexMatchIterator(str1, "VB"));
Console.WriteLine("RegexMatchAllPattern: " + tests.RegexMatchAllPattern(str1, "021A"));
Console.WriteLine("RegexMatchAllPattern: " + tests.RegexMatchAllPattern(str1, "021A+VB"));
Console.WriteLine("RegexMatchAllPattern: " + tests.RegexMatchAllPattern(str1, "VB"));
Console.WriteLine("Benchmark the Matches");
var optionals = new string [] { str1 };
var requireds = new string [] { str2 };
var results = tests.RunTests(optionals, requireds, 1);
FiddleHelper.WriteTable(results);
results = tests.RunTests(optionals, requireds, 10);
FiddleHelper.WriteTable(results);
results = tests.RunTests(optionals, requireds, 100);
FiddleHelper.WriteTable(results);
results = tests.RunTests(optionals, requireds, 1000);
FiddleHelper.WriteTable(results);
results = tests.RunTests(optionals, requireds, 10000);
FiddleHelper.WriteTable(results);
public static bool ContainsAll(string str1, string str2)
.Except(new HashSet<string>(str1.Split(',')))
public class StringContainsAllTests
public List<TestResults> RunTests(string [] optionals, string [] requireds, int iterations)
List<TestResults> results = new List<TestResults>();
results.Add(RunTest("Arrays", optionals, requireds, iterations, Arrays));
results.Add(RunTest("ConcatenatedString", optionals, requireds, iterations, ConcatenatedString));
results.Add(RunTest("FormattedString", optionals, requireds, iterations, FormattedString));
results.Add(RunTest("LinqExcept", optionals, requireds, iterations, LinqExcept));
results.Add(RunTest("LinqHashsetExcept", optionals, requireds, iterations, LinqHashsetExcept));
results.Add(RunTest("RegexMatchIterator", optionals, requireds, iterations, RegexMatchIterator));
results.Add(RunTest("RegexMatchAllPattern", optionals, requireds, iterations, RegexMatchAllPattern));
public TestResults RunTest(string methodName, string [] optionals, string [] requireds, int iterations, Func<string, string, bool> testMethod)
var timer = new System.Diagnostics.Stopwatch();
testMethod(optionals[0], requireds[0]);
var coldStartMilliseconds = timer.Elapsed.TotalMilliseconds;
foreach(var i in Enumerable.Range(0,10))
testMethod(optionals[i % optionals.Length], requireds[i % requireds.Length]);
List<double> results = new List<double>(iterations * optionals.Length * requireds.Length);
var overallTimer = System.Diagnostics.Stopwatch.StartNew();
iterations = Math.Max(1, iterations);
for(int i = 0 ; i < iterations ; i ++)
foreach(var optional in optionals)
foreach(var required in requireds)
result = testMethod(optional, required);
results.Add(timer.Elapsed.TotalMilliseconds);
double average = results.Average();
double sd = results.StdDev();
double variance = results.StdDevVar();
return new TestResults(methodName, optionals.Length * requireds.Length, iterations, results.Count(), overallTimer.Elapsed, coldStartMilliseconds, average, sd, variance);
public bool Arrays(string optionalValuesCSV, string requiredValuesPSV)
string[] str1Arr = optionalValuesCSV.Split(',');
foreach (var s in requiredValuesPSV.Split('+'))
if (!str1Arr.Contains(s))
public bool ConcatenatedString(string optionalValuesCSV, string requiredValuesPSV)
string str1Fixed = "," + optionalValuesCSV + ",";
foreach (var s in requiredValuesPSV.Split('+'))
if (!str1Fixed.Contains("," + s + ","))
public bool FormattedString(string optionalValuesCSV, string requiredValuesPSV)
string str1Fixed = String.Format(",{0},", optionalValuesCSV);
foreach (var s in requiredValuesPSV.Split('+'))
if (!str1Fixed.Contains(String.Format(",{0},", s)))
public bool LinqExcept(string optionalValuesCSV, string requiredValuesPSV)
return !requiredValuesPSV.Split('+')
.Except(optionalValuesCSV.Split(','))
public bool LinqHashsetExcept(string optionalValuesCSV, string requiredValuesPSV)
return !requiredValuesPSV.Split('+')
.Except(new HashSet<string>(optionalValuesCSV.Split(',')))
public bool RegexMatchIterator(string optionalValuesCSV, string requiredValuesPSV)
Regex searchPattern = null;
foreach (var s in requiredValuesPSV.Split('+'))
searchPattern = new Regex("," + s + ",");
if (!searchPattern.IsMatch("," + optionalValuesCSV + ","))
public bool RegexMatchAllPattern(string optionalValuesCSV, string requiredValuesPSV)
var pattern = "(?=.*?\\b" + requiredValuesPSV.Replace("+","\\b)(?=.*?\\b") + "\\b)";
Regex searchPattern = new Regex(pattern);
return searchPattern.IsMatch(optionalValuesCSV);
public TestResults (string method, int testCases, int iterations, int totalTests, TimeSpan elapsed, double coldStart, double meanSeconds, double stdDev, double variance)
public string Method { get;set; }
public int TestCases { get;set; }
public int Iterations { get;set; }
public int TotalTests { get;set; }
public TimeSpan Overall { get;set; }
public double Milliseconds { get { return Overall.TotalMilliseconds; } }
public double ColdStart { get;set; }
public double Mean { get; set; }
public double StdDev { get; set; }
public double Variance { get; set; }
public static class LinqExtensions
public static double StdDev(this IEnumerable<double> values)
foreach (double val in values)
double delta = val - mean;
sum += delta * (val - mean);
stdDev = Math.Sqrt(sum / n);
public static double StdDevVar(this IEnumerable<double> values)
foreach (double val in values)
double delta = val - mean;
sum += delta * (val - mean);
stdDev = Math.Sqrt(sum / (n - 1));
public static string WriteMarkdownTable<T>(this IEnumerable<T> list)
var output = new System.Text.StringBuilder();
var properties = typeof(T).GetProperties();
output.AppendFormat("|{0}|", String.Join("|", properties.Select(p => p.Name)));
output.AppendFormat("|{0}|", String.Join("|", properties.Select(p => new string ('-', p.Name.Length))));
foreach(var item in list)
output.AppendFormat("|{0}|", String.Join("|", properties.Select(p => String.Format("{0}", p.GetValue(item)).Replace('|','~'))));
return output.ToString();