views:

202

answers:

4

We have a list of titles, some of which start with numbers (e.g. 5 Ways to Make Widgets). We would like to sort this as if it were "Five Ways..." without changing the title. We know that some movie places do this, but I can't find info online on how to do it. Any ideas?

+3  A: 

Store both the original title and the spelled-out title.

select OriginalTitle from Movies order by spelledTitle

See also: http://stackoverflow.com/questions/3213/c-convert-integers-into-written-numbers

Jimmy
Same as mine. However, you are assuming the list is of objects of a type with a property named something like Title. It could be a list of strings. In that case the Linq statement doesn't work. (I'd assume the same aswell but we cannot know since the OP doesn't say.)
Sani Huttunen
+1  A: 

In Computer Science, when learning programming, sometimes there is an assignment to convert numbers to text. Like:

526 = Fivehundredtwentysix

This is probably something you'll need in this case.

It is a trivial assignment but it is a good lesson.

Sani Huttunen
+1  A: 

Create a custom comparer see http://support.microsoft.com/kb/320727.

Essentially what you want to do is test if the first character is a number. If it isn't just revert to a standard string compare, if it is then you can do some additional processing to get a textual version of the number.

Once you have this most sort algorithms will allow you to pass the comparer in.

Michael Edwards
A: 

To expand on other people's suggestions:

  1. The hardest part of this is probably the code that transforms a number to an english string representing that number - Sani's programming assignment. I've included a simplified example that may not meet your requirements.
private static string[] digitnames = new string[] 
    { "oh", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
private static string ReplaceDigits(string s)
{
    string convertedSoFar = ""; //could use a StringBuilder if performance is an issue.
    for (int charPos = 0; charPos < s.Length; charPos++)
    {
        if (char.IsNumber(s[charPos]))
        {
            //Add the digit name matching the digit.
            convertedSoFar += digitnames[int.Parse(s[charPos].ToString())];
        }
        else
        {
            //we've reached the end of the numbers at the front of the string. 
            //Add back the rest of s and quit.
            convertedSoFar += s.Substring(charPos);
            break;
        }
    }
    return convertedSoFar;
}

This code turns "101 dalmations" into "oneohone dalmations" and "12 angry men" into "onetwo angry men". A more complete solution could be built, perhaps from Wedge's solution to a slightly different problem. I haven't tested that code, and it isn't designed to handle the string after the digits, but it's probably a good start.

  1. In modern C# (3.0 and higher, I think) you can pass a method name to Sort, rather than explicitly creating an IComparable or IComparer. This is essentially the same idea as Michael's link. Another related option is an anonymous lambda expression which wouldn't even require an external method. Personally I think the code reads more cleanly this way.
private static int NumberReplacingCompare(string strA, string strB)
{
    return ReplaceDigits(strA).CompareTo(ReplaceDigits(strB));
}
private static void OutputSortedStrings()
{
    List strings = new List(File.ReadAllLines(@"D:\Working\MyStrings.txt")); //pull the strings from a file (or wherever they come from
    strings.Sort(NumberReplacingCompare); //sort, using NumberReplacingCompare as the comparison function
    foreach (string s in strings)
    {
        System.Console.WriteLine(s);
    }
}
solublefish