【问题标题】:How can I sort a list of numerical strings? Preferably using LINQ如何对数字字符串列表进行排序?最好使用 LINQ
【发布时间】:2017-12-20 09:08:00
【问题描述】:

我有以下方式的字符串:-

string[] things = new string[] { "1", "10", "2", "1_1", "2_1","3_1" };

想要的输出是:

"1",
"1_1",
"2",
"2_1",
"3_1",
"10",

如何使用 LINQ 实现这一点?

【问题讨论】:

  • 你总是有那种带“_”的格式吗?或者你还有其他角色吗?你能解释一下你在什么情况下需要这个吗?
  • 那些不是特殊字符。他们只是角色。您有一个 字符串 列表,而不是数字,这意味着它们按字母顺序排序。为什么"10" 应该排在最后?你想要什么样的排序?规则是什么?
  • OrderBy 允许您指定任何值作为键,而不仅仅是原始值。您可以解析字符串并返回双/十进制键
  • 欢迎来到 StackOverflow。如果您至少发布自己的尝试来展示您如何尝试解决该问题,它将大大提高您的问题的质量。这也是人们期望在这里看到的 ;) 至少你自己一点点努力 :) 好运
  • 排序规则是:第一个数字,然后如果有下划线,则优先,特殊字符后根据数字排序。下划线描述字符串是子部分。表示“1_1”是 1 的子部分

标签: c# .net linq sorting


【解决方案1】:

是的,您可以将每个部分按_ 拆分,并将第一个字符串部分转换为整数。之后排序时,这将确保10 不在2 之前。然后在第二步中根据最后一个数字订购它

string[] things = new string[] { "5_3", "5_2", "1", "10", "2", "1_1", "2_1", "1_2", "3_1" };

string[] ordered = things.OrderBy(x=>Convert.ToInt32(x.Split('_').First())).                       
                           ThenBy(x=>Convert.ToInt32(x.Split('_').Last())).ToArray();

输出:

编辑:这里是documentation of ThenBy 的链接,以提供信息;)

【讨论】:

    【解决方案2】:

    这个呢?

    string[] strings = new string[] { "1", "10", "2", "1_1", "2_1", "3_1" };
    
    var ordered = from str in strings
                    let weight = double.Parse(str.Replace("_", CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator))
                    let pair = new { Weight = weight, OriginalString = str }
                    orderby pair.Weight
                    select pair.OriginalString;
    

    【讨论】:

      【解决方案3】:

      您可以使用OrderBy 的重载之一,它允许您创建自己的密钥并可能指定您自己的比较器。看起来您想将 _ 视为小数分隔符。

      一种快速而肮脏的方法是将_ 替换为小数分隔符,例如:

      var decSeparator=CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
      
      var orderedThings=things.OrderBy(thing=>double.Parse( thing.Replace("_",decSeparator)) )
                              .ToArray();
      

      这又快又脏,因为它假定_ 只出现一次。如果_ 出现多次,被替换的字符串将不是有效数字

      【讨论】:

      • 感谢课程,更换不是永久性的,只允许正确的排序。投赞成票:)
      • 知道了,谢谢
      【解决方案4】:

      这将为您提供所需的输出:

      string[] things = new string[] { "1", "10", "2", "1_1", "2_1", "3_1" };
      var list =  from row in things select Decimal.Parse(row.Replace("_",CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator));
      list = list.OrderBy(d=> d).ToList();
      var StringList = from row in list select row.ToString("0.#").Replace(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator, "_");
      

      【讨论】:

      • @MongZhu 我得到以下输出:1,1_1,2,2_2,3_1,10
      • @Digambar 10 仍然存在是什么意思? 10 应该是输出中的最大数字,所以它在我的代码的输出中
      • @MongZhu 我也这么认为
      • 我的错,我在测试时犯了一个错误;)对不起
      • 您可以使用 var StringList = from row in list select row.ToString("0.#").Replace(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator, "_");来解决这个问题。我更新了我的代码来解决 CultureInfo
      【解决方案5】:

      如果该格式很严格,您可以解析为 Version 并按此排序:

      string[] orderedThings = things
         .Select(t => new { Thing = t, Numbers = (t + "_0").Split('_') })
         .Where(x => x.Numbers.All(s => s.All(char.IsDigit)))
         .Select(x => new { x.Thing, VersionStr = String.Join(".",x.Numbers.Take(4)) })
         .OrderBy(x => new Version(x.VersionStr))
         .ThenBy(x => x.Thing)
         .Select(x => x.Thing)
         .ToArray();
      

      t + "_0" 技巧对于确保也可以解析单个数字是必要的。一个版本至少需要一个主要部分和次要部分。如果有超过 4 个令牌(主要、次要、构建和修订),这也“有效”。然后只取前4个来初始化Version实例。

      【讨论】:

      • 考虑到它为多个'_'提供的灵活性,这是最好的选择。
      猜你喜欢
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      相关资源
      最近更新 更多