对包含字符串和/或数字的集合进行排序

时间:2018-06-14 09:16:44

标签: c# linq sorting

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

  1. cat(2)
  2. bird(34)
  3. cat + dog(11)
  4. dog(5)
  5. 此外,我有一个特定的必需订单,让我们说:

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

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

    1. dog(5)
    2. bird(34)
    3. cat(2)
    4. cat + dog(11)
    5. 目前我有类似的东西:

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

      但它不起作用。 ThenBy与第一次排序重叠。 在将int.Parse输入ThenBy括号后,我还会获得例外

      帮助我实现这一目标。

3 个答案:

答案 0 :(得分: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();

答案 1 :(得分:1)

与使用正则表达式的@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();

答案 2 :(得分:0)

没有做过检查......数据是完美的,或者一切都在蓬勃发展:

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