如何按前缀数字然后按字母顺序对字符串列表进行排序

时间:2020-08-09 01:48:19

标签: c# sorting

我的目标是将List<string>杂乱地排序为这样的["1", "1a", "2", "2a", "2b", "a", "b"]

我的代码有点长,所以我将其包含在此链接https://dotnetfiddle.net/wZ0dTG中。

我想做的是使用Regex.Split(string, "([0-9]+)")[0]分割字符串,然后根据传递的字符串int.TryParse,以数字或字母顺序对列表进行排序。

正则表达式匹配字符串中包含的所有整数。

直到我应用正则表达式,它都会进行排序。尽管排序,但排序不正确。

应用正则表达式时,出现此错误:

ArgumentException:无法排序,因为IComparer.Compare()方法返回的结果不一致。一个值与自己的比较不相等,或者一个值与另一个值重复比较会产生不同的结果。 IComparer:“ System.Comparison`1 [Ndot_Partnering_Tool.Data.Models.Project

3 个答案:

答案 0 :(得分:1)

对于此特定任务,OrderBy方法非常适合您。我会用它代替正则表达式。 OrderBy使用lambda表达式作为排序的键。 由于此方法使用的字母在数字后面,因此实际上您可以默认进行排序。

您可以这样做:

List<string> List = new List<string>() {"a", "2b", "1a", "1", "2", "2a", "b", "1b" };
List<string> OrderedList = List.OrderBy(x => x).ToList(); 

OrderBy方法返回IEnumerable,因此您必须将其转换回List。

输出:

原始列表:a 2b 1a 1 2 2a b 1b

排序列表:1 1a 1b 2 2a 2b a b

答案 1 :(得分:1)

因此,您必须将字符串拆分为(可选)数字部分和(可选)其余部分。这可以通过正则表达式来完成:

var match = Regex.Match(item, @"(?<number>\d+)?(?<rest>.*)$");

“数字”部分匹配一个或多个数字,但是是可选的(问号),“其余”部分匹配整个字符串的其余部分。

通过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();

(我故意决定将没有前导号的项目放在其余的前面;问题中未指定)。

输出:a,b,1、1a,2、2a,2b,12a

答案 2 :(得分:0)

两个问题:

  1. SplitRegex()在参数“ a”上失败,因为它与正则表达式不匹配(RegEx.Split返回具有一个元素的数组)。您可以使用以下代码:

    返回Regex.Split(x,“([[0-9] +)”)。ElementAtOrDefault(1)? string.Empty;

  2. 当x和y都不能转换为整数时,请为x和y调用CompareString(),但是x和y并不是完整的字符串,它们只是数字部分(并且由于该部分为空)。您需要按原样传递列表项以比较器并在那里提取数字:

     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);
     }
    

并像这样排序列表:

list.Sort(CompareContractNumbers);
相关问题