【问题标题】:How to sort a list of strings by prefix number then alphabetically如何按前缀编号然后按字母顺序对字符串列表进行排序
【发布时间】:2020-08-09 01:48:19
【问题描述】:

我的目标是将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

【问题讨论】:

  • 如果你想要的只是:'["1", "1a", "2", "2a", "2b", "a", "b"]' 那么你可以简单地对字符串进行排序,因为按排序顺序,数字排在字母之前。
  • 列表是否还可以包含“12a”,它应该排在“2a”之前还是之后?
  • @Klaus "12a" 也必须在 "2a" 之后,就好像 12 在 2 之后一样。可能,"100000z" 必须在 "9000z" 之后。

标签: c# sorting


【解决方案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】:

    对于这个特定的任务,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

    【讨论】:

    • 从技术上讲,这不会在 2a 之后对 12a 进行排序,但它可以很好地完成这项工作。我认为我最初问的是不可能的,因为它可能会对两个等效的字符串进行不同的排序。另外,我就是喜欢这个 OrderBy linq。
    【解决方案3】:

    两个问题:

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

      return Regex.Split(x, "([0-9]+)").ElementAtOrDefault(1) ??字符串.空;

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      • 2013-09-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多