Uchendu Nwachuku Uchendu Nwachuku - 2 months ago 10
C# Question

How to group a list of titles by the first letter with linguistic rules?

I have a list of game titles that I am trying to display. Using

OrderBy()
sorts the list according to title rules for the current culture, so for en-US I get a list like this:


  • Arthur's Game

  • The Best Game Ever

  • Carl's Game

  • David's Game

  • Earnest's Game

  • An Even Better Game



That's great and exactly what I want.

But how do I take this list and group it by the first letter (the letter in bold), in a culture-sensitive way? More specifically, how do I get the actual string that
OrderBy()
used to sort the list this way?

I tried looking at
System.Globalization.SortKey.OriginalString
but it just returned the same string it was given.

I know I can always take the sloppy way out and just trim "A", "An" and "The" from the start of the string, but I was hoping .Net had a way to hook into its culture-sensitive sorting logic for a more robust solution.

Edit: It looks like I was mistaken, and
GroupBy()
does not, in fact, sort that way. I messed up with my sample list. So It looks like I will have to just trim away the "A", "An", and "The" prefixes. Thanks to @stuartd for pointing out my error.

Answer Source

I don't know any already implemented solution to sort the titles like required. Since the words you could exclude are not so many (as I believe), you could define your own list of exclusions like

List<string> exclusions = new List<string>()
{
    "the", "an", "a",
};

Based on this exclusions you could order your titles (case insensitive in this implementation) using a simple query ignoring the exlusions you defined:

var orderedTitles = titles.OrderBy(
    t => string.Join(" ", t.Split(' ')
        .Where(s => !exclusions.Any(x => x.Equals(s, StringComparison.OrdinalIgnoreCase)))));

The idea is to split the title by spaces, and join it together without the excluded words. After that a simple order by does the job.

  • A simple track1
  • A simple a track2

If you only need to ignore all exclusions until the first non-excluded word, you could improve the query by using Skip.

var result = titles.OrderBy(
    t => string.Join(" ", t.Split(' ')
        .SkipWhile(s => exclusions.Any(x => x.Equals(s, StringComparison.OrdinalIgnoreCase)))));
  • A simple a track2
  • A simple track1