Can I use a TryParse inside Linq Comparable?

后端 未结 5 1452
野趣味
野趣味 2020-12-03 10:44

A sort of:

Documenti = Documenti
    .OrderBy(o => string.IsNullOrEmpty(o.Note))
    .ThenBy(o => Int32.TryParse(o.Note))
    .ToList();
相关标签:
5条回答
  • 2020-12-03 11:30

    Everyone who uses C#7 or newer scroll to the bottom, everyone else can read the original answer:


    Yes, you can, if you pass the correct parameters to int.TryParse. Both overloads take the int as out-parameter and initialize it inside with the parsed value. So like this:

    int note;
    Documenti = Documenti
        .OrderBy(o => string.IsNullOrEmpty(o.Note))
        .ThenBy(o => Int32.TryParse(o.Note, out note)) 
        .ToList();
    

    The clean approach is using a method that parses to int and returns int? if unparseable:

    public static int? TryGetInt(this string item)
    {
        int i;
        bool success = int.TryParse(item, out i);
        return success ? (int?)i : (int?)null;
    }
    

    Now you can use this query(OrderByDescending because true is "greater" than false):

    Documenti = Documenti.OrderByDescending(d => d.Note.TryGetInt().HasValue).ToList();
    

    It's cleaner than using a local variable that is used in int.TryParse as out parameter.

    Eric Lippert commented another answer of me where he gives an example when it might hurt:

    C# LINQ: How is string("[1, 2, 3]") parsed as an array?


    Update, this has changed with C#7. Now you can declare the variable directly where you use out parameters:

    Documenti = Documenti
    .OrderBy(o => string.IsNullOrEmpty(o.Note))
    .ThenBy(o => Int32.TryParse(o.Note, out int note)) 
    .ToList();
    
    0 讨论(0)
  • 2020-12-03 11:34
    Documenti = Documenti.OrderBy(o =>
            int.TryParse(o.Note, out int val)
                ? val
                : int.MaxValue /* or int.MinValue */
        ).ToList();
    

    Note: Toggling between int.MaxValue and int.MinValue will either put the empty values at the front or the end of the list.

    EDIT: 2020-02-07 Using an inline out variable which was introduced in C# 7

    0 讨论(0)
  • 2020-12-03 11:34

    C# 7 has some new features that make this even easier

    var ints = from a in str.Split(',').Select(s=> new { valid = int.TryParse(s, out int i), result = i })
               where  a.valid
               select a.result;
    

    or as you are asking specifically about sorting

    var ints = from a in str.Split(',')
               orderby (int.TryParse(s, out int i) ? i : 0 )
               select a.result;
    
    0 讨论(0)
  • 2020-12-03 11:37

    You can actually put much more complex logic in the lambda expression:

    List<Doc> Documenti = new List<Doc>() {
            new Doc(""),
            new Doc("1"),
            new Doc("-4"),
            new Doc(null) };
    
    Documenti = Documenti.OrderBy(o => string.IsNullOrEmpty(o.Note)).ThenBy(o => 
    {
        int result;
        if (Int32.TryParse(o.Note, out result))
        {
            return result;
        } else {
            return Int32.MaxValue;
        }
    }).ToList();
    
    foreach (var item in Documenti)
    {
        Console.WriteLine(item.Note ?? "null");
        // Order returned: -4, 1, <empty string>, null
    }
    

    Remember, o => Int32.TryParse(...) is just a shorthand for creating a delegate that just takes in o as a parameter and returns Int32.TryParse(...). You can make it do whatever you want as long as it still is a syntacticly correct method with the correct signature (ex, all code paths return an int)

    0 讨论(0)
  • 2020-12-03 11:41

    That won't produce the expected results b/c TryParse returns a bool rather than int. The easiest thing to do is create a function that returns an int.

    private int parseNote(string note) 
    {   
      int num;   
      if (!Int32.TryParse(note, out num)) 
      {
        num = int.MaxValue; // or int.MinValue - however it should show up in sort   
      }
    
      return num; 
    }
    

    call that function from your sort

    Documenti = Documenti
        .OrderBy(o => parseNote(o.Note))
        .ToList();
    

    you could do it inline too, but, i think a separate method makes the code more readable. i'm sure the compiler will inline it, if it's an optimization.

    0 讨论(0)
提交回复
热议问题