A sort of:
Documenti = Documenti
.OrderBy(o => string.IsNullOrEmpty(o.Note))
.ThenBy(o => Int32.TryParse(o.Note))
.ToList();
That will "ignore" (not order, putting at the end) if o.Note is "" or not an int.
How can I do it?
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();
ThenBy be sorting the boolean success/fail returned from TryParse rather than double value in this case?ThenBy will use the bool returned from TryParse, so all invalid integers will come first, use ThenByDescending if you want the valid first. If you want to sort by the value use for example: ThenBy(o => Int32.TryParse(o.Note, out int note) ? note : int.MinValue).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
int.TryParse in a LINQ query can cause other undesired effects.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)
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.
That won't produce the expected results b/c TryParse returns a bool rather than int It looks like he wants that; he wants to move all items that aren't ints to the end, not order them by their numeric value.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;
EntityFramework