Oosutsuke
Oosutsuke

Reputation: 81

C# - How to sort list string number by linq?

I have a list, each element in the list is a string that contains date and integer in specific format: yyyyMMdd_number.

List<string> listStr = new List<string> { "20170822_10", "20170821_1", "20170823_4", "20170821_10", "20170822_11", "20170822_5",
                                          "20170822_2", "20170821_3", "20170823_6", "20170823_21", "20170823_20", "20170823_2"};

When use method listStr.Sort();

Result as below:

20170821_1
20170821_10
20170821_3
20170822_10
20170822_11
20170822_2
20170822_5
20170823_2
20170823_20
20170823_21
20170823_4
20170823_6

Expected Output:

20170821_1
20170821_3
20170821_10
20170822_2
20170822_5
20170822_10
20170822_11
20170823_2
20170823_4
20170823_6
20170823_20
20170823_21

The way: i think every string(day_number) will split with an underline, then compare and sort by number. But please suggest me LINQ solution or better way to sort in this case.

Upvotes: 1

Views: 4816

Answers (3)

ainwood
ainwood

Reputation: 1048

The answers above are much easier to follow / understand, but purely as an alternative for academic interest, you could do the following:

var sorted = listStr.OrderBy(x => Convert.ToInt32(x.Split('_')[0])*100 + Convert.ToInt32(x.Split('_')[1]));

It works on the premise that the suffix part after the underscore is going to be less than 100, and turns the two elements of the string into an integer with the relative 'magnitude' preserved, that can then be sorted.

The other two methods are much, much easier to follow, but one thing going for my alternative is that it only needs to sort once, so would be a bit faster (although I doubt it is going to matter for any real-world scenario).

Upvotes: 1

David
David

Reputation: 219047

I imagine any numeric ordering would first require converting the value to a numeric type. So you could split on the underscore, sort by the first value, then by the second value. Something like this:

list.OrderBy(x => x.Split('_')[0]).ThenBy(x => int.Parse(x.Split('_')[1]))

You could improve this, if necessary, by creating a class which takes the string representation on its constructor and provides the numeric representations (and the original string representation) as properties. Then .Select() into a list of that class and sort. That class could internally do type checking, range checking, etc.

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726987

Since the dates are in the format that can be ordered lexicographically, you could sort by the date prefix using string ordering, and resolve ties by parsing the integer:

var sorted = listStr
    .OrderBy(s => s.Split('_')[0])
    .ThenBy(s => int.Parse(s.Split('_')[1]));

Demo.

Upvotes: 10

Related Questions