The other day I was presented with the very common problem of turning a comma-separated list of numbers into an array.

Now the classic way of doing this (given a string numbersCSV) is:

string[] splitString = numbersCSV.Split(',');
int?[] intResult = new int?[splitString.Length];
for (int j = 0; j < splitString.Length; j++)
{
    int r;
    if (int.TryParse(splitString[j], out r))
    {
        intResult[j] = r;
    }
    else
    {
        intResult[j] = null;
    }
}

… Or if you want to be more terse about it:

string[] splitString = numbersCSV.Split(',');
int?[] intResult = new int?[splitString.Length];
for (int j = 0; j < splitString.Length; j++)
{
    int r;
    intResult[j] = int.TryParse(splitString[j].Trim(), out r) ? (int?)r : null;
}

I wondered if there was an even terser (and sexier) way using predicates and LINQ extension methods. I came up with three variations (that return List<int?>), all bristling with one-line LINQ-extension / predicate goodness:

IEnumerable<int?> intList2 = numbersCSV.Split(',').Select<string, int?>(
s => { int i; return int.TryParse(s.Trim(), out i) ? i : (int?)null; });

This splits the string and projects the results (using the Select<> extension) into a list of Nullable<int>s using a Func<> lambda.

List<int?> intList3 = new List<int?>(20);
	numbersCSV.Split(',').ToList().ForEach(s => { int i; if (int.TryParse(s.Trim(), out i)) { intList3.Add(i); } else { intList3.Add(null); } });

This one splits the string and calls ForEach<> extension with an Action<> lambda.

IEnumerable<int?> intList1 = numbersCSV.Split(',').ToList().	ConvertAll<int?>(s => { int i; if (int.TryParse(s.Trim(), out i)) { return i; } else { return null; } });

This one splits the string and calls the Convert<> extension with a Converter<> lambda.

Clear as mud.

Of course, the natural question (other than “Huh?”) is how they perform relative to the straightforward way? Without getting into the gory details*, I found that the first method is the best, with a 15% worse execution time as compared to the “classic” way.

Is the savings in vertical space worth the performance hit and illegible code?

… Well, probably not, but I it was a fun learning experience =)


*The gory details: I chose nullable ints because I wanted a little robustness (no exceptions thrown). I constructed random comma-separated lists and did multiple trials of 500,000 loops of the parse routine. To force the enumeration of the ints, I took the sum of the non-null values and printed them out to the console.