【问题标题】:Sorting a collection containing strings and/or numbers对包含字符串和/或数字的集合进行排序
【发布时间】:2023-03-10 08:46:02
【问题描述】:

我有一个 100 个元素的列表,它们看起来像这样:

  1. 猫 (2)
  2. 鸟 (34)
  3. 猫 + 狗 (11)
  4. 狗 (5)

另外,我有一个特定的要求,比如说:

string[] order = {"dog", "bird", "cat", "cat + dog"};

我需要我的方法按上述顺序排序,然后按数字排序,得到结果:

  1. 狗 (5)
  2. 鸟 (34)
  3. 猫 (2)
  4. 猫 + 狗 (11)

目前我有类似的东西:

bool equal = collection
  .OrderBy(i => Array.IndexOf(order, i.Split('(').First()))
  .ThenBy(i => i.Split('(').Last().Replace(")", " "))
  .SequenceEqual(collection2);

但它不起作用。 ThenBy 与第一次排序重叠。 同样在将int.Parse 输入ThenBy 括号后,我得到了一个异常

帮助我实现这一目标。

【问题讨论】:

  • 您是否打算制作自定义比较功能?
  • "list of 100 elements" 是字符串“cat (2)”的元素,或者是具有cat2 属性的元素
  • 将您的 i.Split('(').Last().Replace(")", " ") 解析为数字有帮助吗?即 bool equal = collection .OrderBy(i => Array.IndexOf(order, i.Split('(').First())) .ThenBy(i => int.Parse(i.Split('('). Last().Replace(")", ""))) .SequenceEqual(collection2);
  • @Lucifer 他还有一步:按另一个数组排序一个数组

标签: c# linq sorting


【解决方案1】:

我建议将初始行拆分为匿名类实例:完成(并调试)后,您可以只放入

.OrderBy(item => Array.IndexOf(order, item.name))
.ThenBy(item => item.count)

实施:

  List<string> collection = new List<string> {
    "dog",
    "cat (2)",
    "bird (34)",
    "cat + dog (11)",
    "dog (5)",
  };

  string[] order = { "dog", "bird", "cat", "cat + dog" };

  var result = collection
    .Select(item => item.Split('('))
    .Select(parts => parts.Length == 1 // do we have "(x)" part?
       ? new { name = parts[0].Trim(), count = 1 } // no
       : new { name = parts[0].Trim(), count = int.Parse(parts[1].Trim(')')) }) // yes
    .OrderBy(item => Array.IndexOf(order, item.name)) // now it's easy to work with data
    .ThenBy(item => item.count)
    .Select(item => item.count == 1 // back to the required format
       ? $"{item.name}"
       : $"{item.name} ({item.count})")
    .ToList();

 Console.WriteLine( string.Join(Environment.NewLine, result));

结果:

dog
dog (5)
bird (34)
cat (2)
cat + dog (11)

编辑:您的代码已修改 Trim() 添加到 OrderBy 中; ThenBy 重新设计

  var result = collection
    .OrderBy(i => Array.IndexOf(order, i.Split('(').First().Trim())) // Trim
    .ThenBy(i => i.Contains('(')                                     // two cases:
       ? int.Parse(i.Split('(').Last().Replace(")", ""))             // with "(x)" part
       : 1)                                                          // without
    .ToList();

【讨论】:

    【解决方案2】:

    @Dmitry Bychenko 使用正则表达式的答案完全相同:

    var collection = new List<string> {
        "dog",
        "cat (2)",
        "bird (34)",
        "cat + dog (11)",
        "dog (5)",
    };
    
    string[] order = { "dog", "bird", "cat", "cat + dog" };
    
    var regex = new Regex("^(?<name>.*?)\\s*(\\((?<number>[0-9]+)\\))?$");
    
    var result = collection
      .Select(i =>
        {
          var match = regex.Match(i);
          return new {
              content = i,
              name = match.Groups["name"].Value,
              number = int.TryParse(match.Groups["number"].Value, out int number) 
                ? number 
                : 1 };
        })
      .OrderBy(item => Array.IndexOf(order, item.name))
      .ThenBy(item => item.number)
      .Select(i => i.content)
      .ToList();
    
    Console.WriteLine(string.Join(Environment.NewLine, result));
    Console.ReadLine();
    

    【讨论】:

    • 您可以将\s*添加到模式var regex = new Regex(@"(?&lt;name&gt;.*)\s*\\((?&lt;number&gt;[0-9]+)\\)");中并去掉Trim().OrderBy(item =&gt; Array.IndexOf(order, item.name))
    • 自从default(int) == 0我怀疑应该使用它;可能应该是1... ? number : 1 - 如果数量 - (number) - 被省略,那么 one 提到动物:"dog" - 一只狗,"dog (5)" - 五只狗。
    • @DmitryBychenko 你是对的,它会使代码更好;-) 我还为名称添加了一个非贪婪表达式,否则它将保留空格。
    【解决方案3】:

    未进行任何检查...数据完美无缺或一切顺利:

    var res = (from x in collection
               let ix = x.LastIndexOf(" (")
               orderby Array.IndexOf(order, ix != -1 ? x.Remove(ix) : x),
                   ix != -1 ? int.Parse(x.Substring(ix + 2, x.Length - 1 - (ix + 2))) : 0
               select x).ToArray();
    

    注意ix != -1 的双重处理。在orderby的第二行(即函数式LINQ中的ThenBy()),如果ix == -1则值为: 0

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 2019-05-26
      • 2021-08-12
      • 2020-03-21
      • 1970-01-01
      • 2011-08-24
      • 2020-02-18
      相关资源
      最近更新 更多