In the sprit of playing with a string chop question on stackoverflow… I somehow got myself into the middle of some fun code profiling. So this is a report of the code and results.
(this is related to a previous most I made as well http://hackersbasement.com/?p=134)
Charted Short String Results
| Person | Version | Run 1 | Run 2 | Run 3 |
| Str | SB | J | Str | SB | J | Str | SB | J |
| Alan M | 1 | 8484 | | | 707 | | | 1477 | | |
| 2 | 43526 | | | 616 | | | 700 | | |
| 3 | 7224 | | | 707 | | | 2296 | | |
| Aric TenEyck | 1 | | 15477 | 560 | | 385 | 175 | | 301 | 273 |
| 2 | | 31773 | 357 | | 133 | 322 | | 168 | 294 |
| Fredou | 1 | 14567 | | | 322 | | | 154 | | |
| Joel Coehoorn | 1 | | 51282 | 735 | | 350 | 308 | | 1071 | 329 |
| 2 | 22876 | | | 161 | | | 140 | | |
| Martin | 1 | 14357 | | | 140 | | | 98 | | |
| 2 | 12138 | | | 112 | | | 84 | | |
| 3 | | 39109 | 1127 | | 119 | 147 | | 119 | 287 |
| Matthew Whited | 1 | | 29211 | 11179 | | 518 | 665 | | 378 | 448 |
| 2 | | 45794 | 1484 | | 546 | 182 | | 301 | 679 |
| 3 | 11697 | | | 210 | | | 217 | | |
| 4 | 14322 | | | 175 | | | 147 | | |
| Tim J | 1 | | 38997 | 784 | | 91 | 168 | | 168 | 280 |
Charted Long String Results
| Person | Version | Run 1 | Run 2 | Run 3 |
| Str | SB | J | Str | SB | J | Str | SB | J |
| Alan M | 1 | 46550 | | | 38535 | | | 40677 | | |
| 2 | 45899 | | | 39312 | | | 39858 | | |
| 3 | 28910 | | | 303254 | | | 26845 | | |
| Aric TenEyck | 1 | | 28987 | 3647 | | 2240 | 1904 | | 2198 | 3563 |
| 2 | | 35364 | 3661 | | 4767 | 4284 | | 5096 | 5285 |
| Fredou | 1 | 13699 | | | 4256 | | | 9520 | | |
| Joel Coehoorn | 1 | | 49686 | 1344 | | 581 | 700 | | 812 | 840 |
| 2 | 31304 | | | 329 | | | 329 | | |
| Martin | 1 | 15050 | | | 308 | | | 336 | | |
| 2 | 12537 | | | 350 | | | 469 | | |
| 3 | | 34027 | 1099 | | 406 | 434 | | 532 | 777 |
| Matthew Whited | 1 | | 69566 | 11886 | | 882 | 819 | | 651 | 875 |
| 2 | | 39620 | 2254 | | 581 | 497 | | 658 | 707 |
| 3 | 17227 | | | 441 | | | 588 | | |
| 4 | 27349 | | | 441 | | | 616 | | |
| Tim J | 1 | | 36260 | 142233 | | 672 | 1008 | | 497 | 1610 |
Results for Short string "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
============================================
StringBuilder: MatthewWhited1 Ticks: 29211
StringBuilder: MatthewWhited2 Ticks: 45794
Join: MatthewWhited1 Ticks: 11179
Join: MatthewWhited2 Ticks: 1484
String: MatthewWhited3 Ticks: 11697
String: MatthewWhited4 Ticks: 14322
String: AlanM_1 Ticks: 8484
String: AlanM_2 Ticks: 43526
String: AlanM_3 Ticks: 7224
StringBuilder: AricTenEyck1 Ticks: 15477
StringBuilder: AricTenEyck2 Ticks: 31773
Join: AricTenEyck1 Ticks: 560
Join: AricTenEyck2 Ticks: 357
String: Martin1 Ticks: 14357
String: Martin2 Ticks: 12138
StringBuilder: Martin3 Ticks: 39109
Join: Martin3 Ticks: 1127
String: JoelCoehoorn2 Ticks: 22876
StringBuilder: JoelCoehoorn1 Ticks: 51282
Join: JoelCoehoorn1 Ticks: 735
StringBuilder: TimJ Ticks: 38997
Join: TimJ Ticks: 784
String: Fredou1 Ticks: 14567
============================================
StringBuilder: MatthewWhited1 Ticks: 518
StringBuilder: MatthewWhited2 Ticks: 546
Join: MatthewWhited1 Ticks: 665
Join: MatthewWhited2 Ticks: 182
String: MatthewWhited3 Ticks: 210
String: MatthewWhited4 Ticks: 175
String: AlanM_1 Ticks: 707
String: AlanM_2 Ticks: 616
String: AlanM_3 Ticks: 707
StringBuilder: AricTenEyck1 Ticks: 385
StringBuilder: AricTenEyck2 Ticks: 133
Join: AricTenEyck1 Ticks: 175
Join: AricTenEyck2 Ticks: 322
String: Martin1 Ticks: 140
String: Martin2 Ticks: 112
StringBuilder: Martin3 Ticks: 119
Join: Martin3 Ticks: 147
String: JoelCoehoorn2 Ticks: 161
StringBuilder: JoelCoehoorn1 Ticks: 350
Join: JoelCoehoorn1 Ticks: 308
StringBuilder: TimJ Ticks: 91
Join: TimJ Ticks: 168
String: Fredou1 Ticks: 322
============================================
StringBuilder: MatthewWhited1 Ticks: 378
StringBuilder: MatthewWhited2 Ticks: 301
Join: MatthewWhited1 Ticks: 448
Join: MatthewWhited2 Ticks: 679
String: MatthewWhited3 Ticks: 217
String: MatthewWhited4 Ticks: 147
String: AlanM_1 Ticks: 1477
String: AlanM_2 Ticks: 700
String: AlanM_3 Ticks: 2296
StringBuilder: AricTenEyck1 Ticks: 301
StringBuilder: AricTenEyck2 Ticks: 168
Join: AricTenEyck1 Ticks: 273
Join: AricTenEyck2 Ticks: 294
String: Martin1 Ticks: 98
String: Martin2 Ticks: 84
StringBuilder: Martin3 Ticks: 119
Join: Martin3 Ticks: 287
String: JoelCoehoorn2 Ticks: 140
StringBuilder: JoelCoehoorn1 Ticks: 1071
Join: JoelCoehoorn1 Ticks: 329
StringBuilder: TimJ Ticks: 168
Join: TimJ Ticks: 280
String: Fredou1 Ticks: 154
Results for Long string "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" * 68
============================================
StringBuilder: MatthewWhited1 Ticks: 69566
StringBuilder: MatthewWhited2 Ticks: 39620
Join: MatthewWhited1 Ticks: 11886
Join: MatthewWhited2 Ticks: 2254
String: MatthewWhited3 Ticks: 17227
String: MatthewWhited4 Ticks: 27349
String: AlanM_1 Ticks: 46550
String: AlanM_2 Ticks: 45899
String: AlanM_3 Ticks: 28910
StringBuilder: AricTenEyck1 Ticks: 28987
StringBuilder: AricTenEyck2 Ticks: 35364
Join: AricTenEyck1 Ticks: 3647
Join: AricTenEyck2 Ticks: 3661
String: Martin1 Ticks: 15050
String: Martin2 Ticks: 12537
StringBuilder: Martin3 Ticks: 34027
Join: Martin3 Ticks: 1099
String: JoelCoehoorn2 Ticks: 31304
StringBuilder: JoelCoehoorn1 Ticks: 49686
Join: JoelCoehoorn1 Ticks: 1344
StringBuilder: TimJ Ticks: 36260
Join: TimJ Ticks: 142233
String: Fredou1 Ticks: 13699
============================================
StringBuilder: MatthewWhited1 Ticks: 882
StringBuilder: MatthewWhited2 Ticks: 581
Join: MatthewWhited1 Ticks: 819
Join: MatthewWhited2 Ticks: 497
String: MatthewWhited3 Ticks: 441
String: MatthewWhited4 Ticks: 441
String: AlanM_1 Ticks: 38535
String: AlanM_2 Ticks: 39312
String: AlanM_3 Ticks: 303254
StringBuilder: AricTenEyck1 Ticks: 2240
StringBuilder: AricTenEyck2 Ticks: 4767
Join: AricTenEyck1 Ticks: 1904
Join: AricTenEyck2 Ticks: 4284
String: Martin1 Ticks: 308
String: Martin2 Ticks: 350
StringBuilder: Martin3 Ticks: 406
Join: Martin3 Ticks: 434
String: JoelCoehoorn2 Ticks: 329
StringBuilder: JoelCoehoorn1 Ticks: 581
Join: JoelCoehoorn1 Ticks: 700
StringBuilder: TimJ Ticks: 672
Join: TimJ Ticks: 1008
String: Fredou1 Ticks: 4256
============================================
StringBuilder: MatthewWhited1 Ticks: 651
StringBuilder: MatthewWhited2 Ticks: 658
Join: MatthewWhited1 Ticks: 875
Join: MatthewWhited2 Ticks: 707
String: MatthewWhited3 Ticks: 588
String: MatthewWhited4 Ticks: 616
String: AlanM_1 Ticks: 40677
String: AlanM_2 Ticks: 39858
String: AlanM_3 Ticks: 26845
StringBuilder: AricTenEyck1 Ticks: 2198
StringBuilder: AricTenEyck2 Ticks: 5096
Join: AricTenEyck1 Ticks: 3563
Join: AricTenEyck2 Ticks: 5285
String: Martin1 Ticks: 336
String: Martin2 Ticks: 469
StringBuilder: Martin3 Ticks: 532
Join: Martin3 Ticks: 777
String: JoelCoehoorn2 Ticks: 329
StringBuilder: JoelCoehoorn1 Ticks: 812
Join: JoelCoehoorn1 Ticks: 840
StringBuilder: TimJ Ticks: 497
Join: TimJ Ticks: 1610
String: Fredou1 Ticks: 9520
Test code
#define OUTPUT_RESULTS_
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.IO;
using System.Threading;
namespace StringChop20
{
//http://stackoverflow.com/questions/1009839/net-split-by-length/
class Program
{
static readonly string s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static readonly int len = 12;
static readonly byte[] bytes = Encoding.UTF8.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
static string logFile = null;
static void Main(string[] args)
{
logFile = "results_" + DateTime.Now.ToString("yyyyMMdd_hhmmss") + ".txt";
Thread.CurrentThread.Priority = ThreadPriority.Highest;
for (int i = 0; i < 3; i++)
{
WriteLine("============================================");
RunTestSB(MatthewWhited1);
RunTestSB(MatthewWhited2);
RunTestJoin(MatthewWhited1);
RunTestJoin(MatthewWhited2);
RunTest(MatthewWhited3);
RunTest(MatthewWhited4);
RunTest(AlanM_1);
RunTest(AlanM_2);
RunTest(AlanM_3);
RunTestSB(AricTenEyck1);
RunTestSB(AricTenEyck2);
RunTestJoin(AricTenEyck1);
RunTestJoin(AricTenEyck2);
RunTest(Martin1);
RunTest(Martin2);
RunTestSB(Martin3);
RunTestJoin(Martin3);
RunTest(JoelCoehoorn2);
RunTestSB(JoelCoehoorn1);
RunTestJoin(JoelCoehoorn1);
RunTestSB(TimJ);
RunTestJoin(TimJ);
RunTest(Fredou1);
GC.Collect();
GC.WaitForPendingFinalizers();
}
//Console.ReadLine();
}
static object _syncLock = new object();
static void WriteLine(string message)
{
lock (_syncLock)
{
File.AppendAllText(logFile, message + "\r\n");
Console.WriteLine(message);
}
}
delegate string MethodRunner();
delegate IEnumerable OtherRunner();
static void RunTest(MethodRunner testMethod)
{
Stopwatch sw = Stopwatch.StartNew();
string result = testMethod();
sw.Stop();
WriteLine("String: " + testMethod.Method.Name + " Ticks: " + sw.ElapsedTicks.ToString());
#if OUTPUT_RESULTS
WriteLine(result);
WriteLine("-----------");
#endif
}
static void RunTestJoin(OtherRunner testMethod)
{
Stopwatch sw = Stopwatch.StartNew();
string result = testMethod().WithJoin();
sw.Stop();
WriteLine("Join: " + testMethod.Method.Name + " Ticks: " + sw.ElapsedTicks.ToString());
#if OUTPUT_RESULTS
WriteLine(result);
WriteLine("-----------");
#endif
}
static void RunTestSB(OtherRunner testMethod)
{
Stopwatch sw = Stopwatch.StartNew();
string result = testMethod().WithStringBuilder();
sw.Stop();
WriteLine("StringBuilder: " + testMethod.Method.Name + " Ticks: " + sw.ElapsedTicks.ToString());
#if OUTPUT_RESULTS
WriteLine(result);
WriteLine("-----------");
#endif
}
static IEnumerable MatthewWhited1()
{
char[] chopMeArray = s.ToCharArray();
int totalLength = s.Length;
int partCount = (totalLength / len) + ((totalLength % len == 0) ? 0 : 1);
int posIndex = 0;
char[] part = new char[len];
string[] parts = new string[partCount];
int get = len;
for (int i = 0; i < partCount; i++)
{
get = Math.Min(len, totalLength - posIndex);
Array.Copy(chopMeArray, posIndex, part, 0, get);
parts[i] = new string(part, 0, get);
posIndex += len;
}
return parts;
}
static IEnumerable MatthewWhited2()
{
char[] chopMeArray = s.ToCharArray();
int totalLength = s.Length;
int partCount = (totalLength / len) + ((totalLength % len == 0) ? 0 : 1);
int posIndex = 0;
char[] part = new char[len];
string[] parts = new string[partCount];
int get = len;
for (int i = 0; i < partCount; i++)
{
get = Math.Min(len, totalLength - posIndex);
Array.Copy(chopMeArray, posIndex, part, 0, get);
yield return new string(part, 0, get);
posIndex += len;
}
}
static string MatthewWhited3()
{
char[] chopMeArray = s.ToCharArray();
int totalLength = s.Length;
int partCount = (totalLength / len) + ((totalLength % len == 0) ? 0 : 1);
int posIndex = 0;
char[] part = new char[len];
string[] parts = new string[partCount];
int get = len;
for (int i = 0; i < partCount; i++)
{
get = Math.Min(len, totalLength - posIndex);
Array.Copy(chopMeArray, posIndex, part, 0, get);
parts[i] = new string(part, 0, get);
posIndex += len;
}
return string.Join("\r\n", parts) + "\r\n";
}
static string MatthewWhited4()
{
char[] chopMeArray = s.ToCharArray();
int totalLength = s.Length;
int partCount = (totalLength / len) + ((totalLength % len == 0) ? 0 : 1);
int posIndex = 0;
char[] part = new char[len];
StringBuilder sb = new StringBuilder();
int get = len;
for (int i = 0; i < partCount; i++)
{
get = Math.Min(len, totalLength - posIndex);
Array.Copy(chopMeArray, posIndex, part, 0, get);
sb.AppendLine(new string(part, 0, get));
posIndex += len;
}
return sb.ToString();
}
static string AlanM_1()
{
return Regex.Replace(s, @"(?<=\G.{12})", "\r\n");
}
static Regex rx0 = new Regex(@"(?<=\G.{12})");
static string AlanM_2()
{
return rx0.Replace(s, "\r\n");
}
static Regex rx1 = new Regex(".{12}");
static string AlanM_3()
{
return Regex.Replace(s, @"(?<=\G.{12})", "\r\n");
}
static IEnumerable AricTenEyck1()
{
List output = new List();
string s2 = s;
while (s2.Length > len)
{
output.Add(s2.Substring(0, len) + "\n");
//Aric I had to change this next line
// to add the asignement (or else this was an infinate loop
s2 = s2.Remove(0, len);
}
//this would add an extra blank line
output.Add(s2 + "\n");
return output;
}
//I added a Iterator version for you as well
static IEnumerable AricTenEyck2()
{
string s2 = s;
while (s2.Length > len)
{
yield return s2.Substring(0, len) + "\n";
s2 = s2.Remove(0, len);
}
yield return s2+ "\n";
}
static string Martin1()
{
StringBuilder sb = new StringBuilder(s.Length + (int)(s.Length / len) + 1);
int start = 0;
for (start = 0; start < s.Length - len; start += len)
{
sb.Append(s.Substring(start, len));
sb.Append("\n");
}
sb.Append(s.Substring(start));
return sb.ToString();
}
//Martin I added this version to match with the others
static string Martin2()
{
StringBuilder sb = new StringBuilder(s.Length + (int)(s.Length / len) + 1);
int start = 0;
for (start = 0; start < s.Length - len; start += len)
sb.AppendLine(s.Substring(start, len));
sb.AppendLine(s.Substring(start));
return sb.ToString();
}
//Martin I added this version to match with the others
static IEnumerable Martin3()
{
StringBuilder sb = new StringBuilder(s.Length + (int)(s.Length / len) + 1);
int start = 0;
for (start = 0; start < s.Length - len; start += len)
yield return s.Substring(start, len);
yield return s.Substring(start);
}
static string SLaks()
{
return Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
}
static IEnumerable JoelCoehoorn1()
{
var buf = new char[len];
using (var rdr = new StringReader(s))
{
int l;
l = rdr.ReadBlock(buf, 0, len);
while (l > 0)
{
yield return (new string(buf, 0, l)) + Environment.NewLine;
l = rdr.ReadBlock(buf, 0, len);
}
}
}
static string JoelCoehoorn2()
{
char[] buf = new char[s.Length + (int)Math.Ceiling(s.Length / (double)len)];
using (var rdr = new StringReader(s))
{
for (int i = 0; i < buf.Length - len; i++)
{
rdr.ReadBlock(buf, i, len);
i += len; buf[i] = '\n';
if (i < s.Length)
rdr.ReadBlock(buf, i, s.Length - i); buf[buf.Length - 1] = '\n';
}
}
return new string(buf);
}
static IEnumerable TimJ()
{
int i = 0; while (i < s.Length)
{
yield return i + len <= s.Length ? s.Substring(i, len) : s.Substring(i);
i += len;
}
}
static string Fredou1()
{
var s2 = s;
StringBuilder n = new StringBuilder(); int chopSize = 0;
while (!string.IsNullOrEmpty(s2))
{
chopSize = s2.Length > len ? len : s2.Length;
n.Append(s2.Substring(0, chopSize) + "\r\n");
s2 = s2.Remove(0, chopSize);
}
return n.ToString();
}
}
// for Robert and others that are interested in the
// string.Join v. StringBuilder I will test both of these
public static class Extensions
{
public static string WithJoin(this IEnumerable input)
{
return string.Join("\r\n", input.ToArray()) + "\r\n";
}
public static string WithStringBuilder(this IEnumerable input)
{
var sb = new StringBuilder();
foreach (var item in input)
sb.AppendLine(item);
return sb.ToString();
}
}
}