My goal is to sort a List<string>
in messy order to an order like this ["1", "1a", "2", "2a", "2b", "a", "b"]
My code is a little long, so I've included it at this link https://dotnetfiddle.net/wZ0dTG .
What I'm trying to do is split the strings using Regex.Split(string, "([0-9]+)")[0]
then based on which strings pass int.TryParse
, I sort the list numerically or alphabetically.
The regex matches all the integers contained within the string.
Until I apply the regex, it sorts. Although it sorts, it doesn't sort them properly.
When I apply the regex, I get this error:
ArgumentException: Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: 'System.Comparison`1[Ndot_Partnering_Tool.Data.Models.Project
For this particular task the OrderBy method is perfect for you. I would use that instead of Regex. OrderBy uses lambda expressions as a key to sort. Since letters are after numbers in the alphabet this method is using, you can actually just sort by default.
You can do:
List<string> List = new List<string>() {"a", "2b", "1a", "1", "2", "2a", "b", "1b" };
List<string> OrderedList = List.OrderBy(x => x).ToList();
The OrderBy method returns IEnumerable so you have to convert it back to List.
Output:
The original list: a 2b 1a 1 2 2a b 1b
The ordered list: 1 1a 1b 2 2a 2b ab
So you have to split your strings into an (optional) numeric part and an (optional) rest. This can be done by a Regex:
var match = Regex.Match(item, @"(?<number>\d+)?(?<rest>.*)$");
The "number" part matches one or more digits, but is optional (question mark), the "rest" part matches the whole rest of the string.
Sorting via Linq:
var input = new List<string>{ "12a", "1", "1a", "2", "2a", "2b", "a", "b", "12a" };
var sorted = input.OrderBy(item =>
{
var match = Regex.Match(item, @"(?<number>\d+)?(?<rest>.*)$");
return Tuple.Create(match.Groups["number"].Success ? int.Parse(match.Groups["number"].Value) : -1, match.Groups["rest"].Value);
}).ToList();
(I deliberately decided to put the items without a leading number before the rest; this was not specified in the question).
Output: a, b, 1, 1a, 2, 2a, 2b, 12a
Two problems:
SplitRegex() failes on argument "a" because it does not match regex (RegEx.Split returns array with one element). You can use this code:
return Regex.Split(x, "([0-9]+)").ElementAtOrDefault(1)?? string.Empty;
When neither x nor y can be converted to integer, you call CompareString() for x and y, but x and y are not whole strings, they are only numerical parts (and because of that empty). You need to pass list items as is to comparer and extract numbers there:
bool leftcanconvertflag = Int32.TryParse(SplitRegex(x), out leftconvertresult); bool rightcanconvertflag = Int32.TryParse(SplitRegex(y), out rightconvertresult); if (leftcanconvertflag &&;rightcanconvertflag) { compareresult = -1; } if (.leftcanconvertflag && rightcanconvertflag) { compareresult = 1; } if (leftcanconvertflag && rightcanconvertflag) { compareresult = leftconvertresult,CompareTo(rightconvertresult); } if (!leftcanconvertflag && !rightcanconvertflag) { compareresult = CompareString(x, y); }
and sort list like this:
list.Sort(CompareContractNumbers);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.