【问题标题】:LINQ Sort Numeric Data Only But Retain The List IntactLINQ 仅对数字数据进行排序,但保持列表完整
【发布时间】:2020-06-14 20:03:55
【问题描述】:

我有以下程序。我的数据类型都是字符串。从列表中,我想对那些具有数值的条目进行排序。那些没有数字数据的条目将始终位于最后一项。这是我的代码。请帮忙。

 class Program
{
    static void Main(string[] args)
    {
        var persons = new List<Person>();
        persons.Add(new Person { Name = "John",   Position = "100" });
        persons.Add(new Person { Name = "Peter",  Position = "78"  });
        persons.Add(new Person { Name = "Larry",  Position = "NA"  });
        persons.Add(new Person { Name = "Lovely", Position = ""    });
        persons.Add(new Person { Name = "Rose",   Position = "50"  });
        persons.Add(new Person { Name = "Drew",   Position = "34"  });

        //Help me do the sorting for position that is a number. Priority in sorting are positions which are numbers
        var sortedPersons = persons.OrderBy(x=>double.Parse(x.Position)).ToList();
        foreach (var person in sortedPersons)
            Console.WriteLine("Name: {0}, Position: {1}", person.Name, person.Position);
        Console.ReadLine();
    }
}
public class Person
{
    public string Name { get; set; }
    public string Position { get; set; }
}

根据我的示例,我想将项目排序为

  1. 画了
  2. 玫瑰
  3. 彼得
  4. 约翰
  5. 可爱的
  6. 拉里

(对于 Lovely 和 Larry 来说,他们的排序方式对我来说并不重要,只要我正确排序 Drew 给 John)。

【问题讨论】:

    标签: c# list linq sorting


    【解决方案1】:

    尝试改用.TryParse(),并将最大值分配给无法解析的任何内容

    您可以使用double.MaxValuedouble.PositiveInfinity 作为默认值。后者是两者中较大的一个。

    persons.OrderBy(x => double.TryParse(x.Position, out double d) ? d : double.PositiveInfinity)
    

    【讨论】:

    • 非常感谢!
    【解决方案2】:

    您可以实现自定义IComparer&lt;string&gt; 并将其实例作为第二个参数传递给OrderBy 方法

    public class PositionComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            double xValue = int.TryParse(x, out var xParsed) ? xParsed : double.PositiveInfinity;
            double yValue = int.TryParse(y, out var yParsed) ? yParsed : double.PositiveInfinity;
    
            return xValue.CompareTo(yValue);
        }
    }
    

    使用示例

    var sortedPersons = persons.OrderBy(x => x.Position, new PositionComparer()).ToList();
    

    它提供了正确的顺序,并允许您重复使用此代码来比较代码其他位置的此类值。

    Name: Drew, Position: 34
    Name: Rose, Position: 50
    Name: Peter, Position: 78
    Name: John, Position: 100
    Name: Larry, Position: NA
    Name: Lovely, Position:
    

    IMO,它也比Linq 方法和谓词更容易理解、维护和调试

    【讨论】:

    • 如果Position 看起来是"2147483647"(即int.MaxValue),则认为它等于任何 nin 数值(如"bla-bla-bla")。所以我们可以有"bla-bla-bla", "2147483647", "non-numeric" 订单
    • @DmitryBychenko OP 声明 对于 Lovely 和 Larry 来说,它们的排序方式对我来说并不重要因此,非数字项目的顺序并不重要
    • persons.Add(new Person { Name = "Rose", Position = "2147483647" }); 使 Rose 等于any Person 与非数字 Position
    • 切换到floatdouble解析和使用infinity很容易解决这个问题,OP在这里没有提到任何边缘情况
    • 这个解决方案需要一个专门的类,看起来像“老式”C#,但至少我发现与其他依赖 LINQ 谓词和元组的方法相比,它更易于理解、调试和维护。
    【解决方案3】:

    如果Position 必须是有效的int(例如,Position = "7.83e+1" 被认为是不是数字并且应该在列表的末尾)我们可以按元组排序:

      var sortedPersons = persons
        .OrderBy(item => (!int.TryParse(item.Position, out var v), v))
        .ToList();
    

    在这里,我们首先按元组的Item1 排序,确定item.Position 是否为int

    !int.TryParse(item.Position, out int v)
    

    所以有效的整数排在第一位。然后我们按照元组的Item2 进行排序,也就是解析值

    v
    

    订购Positions。如果Position 应该是double(例如,Position = "-7.83e-10"完全有效),您可以使用 Innat3 的 解决方案或将int 更改为double

      var sortedPersons = persons
        .OrderBy(item => (!double.TryParse(item.Position, out var v), v))
        .ToList();
    

    【讨论】:

      【解决方案4】:
      var sortedPersons = persons.Where(x => int.TryParse(x.Position, out int res))
                                 .OrderBy(x => int.Parse(x.Position))
                                 .Concat(persons.Where(x => ! int.TryParse(x.Position, out int res)));
      

      【讨论】:

      • 您能否详细说明您的答案,以便其他不熟悉该语言的人了解发生了什么?
      猜你喜欢
      • 2018-04-04
      • 1970-01-01
      • 1970-01-01
      • 2020-12-20
      • 1970-01-01
      • 2012-04-09
      • 2019-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多