Monday, 20 March 2017

A better c# string.Join supporting "and" or "or" for the final item

C# developers often have to convert a list of items into a human-readable list.
For example, if you have a string array: "a", "b", "c", "d", you may want the output to be:

'a', 'b', 'c' and 'd'

Here is a way to do that using a C# extension method:

Comment welcome.  I will update with improvements as suggestions come in:

Extension method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  public static string ToHumanReadableString(this IEnumerable<object> enumerable, string quoteWith = "'", string delimitWith = ", ", string delimitLastWith = " or ")
  {
   if (enumerable == null)
   {
    return string.Empty;
   }
   var list = enumerable.ToList();
   return !list.Any()
    ? string.Empty
    : list.Count == 1
     ? $"{quoteWith}{list.Single()}{quoteWith}"
     : $"{string.Join(delimitWith ?? string.Empty, list.Take(list.Count - 1).Select(item => $"{quoteWith}{item}{quoteWith}"))}{delimitLastWith}{quoteWith}{list.Last()}{quoteWith}";
  }

XUnit tests:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  [Fact]
  public void JoinForHumansTest()
  {
   Assert.Equal("'a'", new List<string> {"a"}.ToHumanReadableString());
   Assert.Equal("''", new string[] { null }.ToHumanReadableString());
   Assert.Equal("'a'", new[] { "a" }.ToHumanReadableString());
   Assert.Equal("'a' or 'b'", new[] { "a", "b" }.ToHumanReadableString());
   Assert.Equal("'a' or ''", new[] { "a", null }.ToHumanReadableString());
   Assert.Equal("'a', 'b' or 'c'", new[] {"a", "b", "c"}.ToHumanReadableString());
   Assert.Equal("'a', 'b', 'c' or 'd'", new[] {"a", "b", "c", "d"}.ToHumanReadableString());
   Assert.Equal("'a';'b';'c' or 'd'", new[] {"a", "b", "c", "d"}.ToHumanReadableString(delimitWith: ";"));
   Assert.Equal("'a', 'b', 'c' and 'd'", new[] {"a", "b", "c", "d"}.ToHumanReadableString(delimitLastWith: " and "));
   Assert.Equal("a, b, c or d", new[] {"a", "b", "c", "d"}.ToHumanReadableString(string.Empty));
   Assert.Equal("abcd", new[] {"a", "b", "c", "d"}.ToHumanReadableString(null, null, null));
   Assert.Equal("", ((string[]) null).ToHumanReadableString(null, null, null));
  }