Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
286 views
in Technique[技术] by (71.8m points)

c# - Linq - Order by number then letters

I have a list of strings, and these strings contain numbers and words.

What I wanted to do is order it by the numbers (numeric order) followed by the words (alphabetical order)

My list does not contain a mix of the two... here is an example

1, 5, 500 , LT, RT, 400 -> LINQ -> 1, 5, 400, 500, LT, RT

Here is a example of what I have, it works but I was wondering if there is a better way of writing it?

            int results = 0;
            // Grabs all voltages
            var voltage = ActiveRecordLinq.AsQueryable<Equipment>()
                .OrderBy(x => x.Voltage)
                .Select(x => x.Voltage)
                .Distinct()
                .ToList();
            // Order by numeric
            var numberVoltage = voltage
                .Where( x => int.TryParse(x, out results))
                .OrderBy( x => Convert.ToInt32(x));
            // Then by alpha
            var letterVoltage = voltage
                .Where(x=> !String.IsNullOrEmpty(x))
                .Where(x => !int.TryParse(x, out results))
                .OrderBy(x => x);

            return numberVoltage.Union(letterVoltage)

Thanks for the help!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Given that you're doing it all in-process (as you've got a ToList call) I think I'd just use a custom comparer:

return ActiveRecordLinq.AsQueryable<Equipment>()
                       .Select(x => x.Voltage)
                       .Distinct()
                       .AsEnumerable() // Do the rest in-process
                       .Where(x => !string.IsNullOrEmpty(x))
                       .OrderBy(x => x, new AlphaNumericComparer())
                       .ToList();

Where AlphaNumericComparer implements IComparer<string>, something like this:

public int Compare(string first, string second)
{
    // For simplicity, let's assume neither is null :)

    int firstNumber, secondNumber;
    bool firstIsNumber = int.TryParse(first, out firstNumber);
    bool secondIsNumber = int.TryParse(second, out secondNumber);

    if (firstIsNumber)
    {
        // If they're both numbers, compare them; otherwise first comes first
        return secondIsNumber ? firstNumber.CompareTo(secondNumber) : -1;
    }
    // If second is a number, that should come first; otherwise compare
    // as strings
    return secondIsNumber ? 1 : first.CompareTo(second);
}

You could use a giant conditional for the latter part:

public int Compare(string first, string second)
{
    // For simplicity, let's assume neither is null :)

    int firstNumber, secondNumber;
    bool firstIsNumber = int.TryParse(first, out firstNumber);
    bool secondIsNumber = int.TryParse(second, out secondNumber);

    return firstIsNumber 
        ? secondIsNumber ? firstNumber.CompareTo(secondNumber) : -1;
        : secondIsNumber ? 1 : first.CompareTo(second);
}

... but in this case I don't think I would :)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...