简体   繁体   中英

C# LINQ Orderby - How does true/false affect orderby?

I was studying a bit of LINQ ordering as I have a list of Ids, and I need to order them sequentially. However, there are certain ids that need to take precedence over the standard ordering.

Given this C# code (which can be pasted into .NET Fiddle to test) the ordering works as I need it to, but I don't understand why a not ( ! ) operator on a contains is giving me the correct ordering?

My expected ordering output is ( 5, 1, 2, 3, 4, 6, 7, 8, 9 ).

If I have a Contains in my ordering, shouldn't it give ordering priority to the rows that returned true? Instead it appears to give ordering priority to rows that return false.

using System.Linq;
using System;

public class Program
{
  public static void Main()
  {
    var numbersToFilterBy = new [] {5, 11, 20};

    var x = new [] {new XClass(){Id = 1}, new XClass(){Id = 9}, new XClass(){Id = 5}, new XClass(){Id = 3}, new XClass(){Id = 4}, new XClass(){Id = 2}, new XClass(){Id = 6}, new XClass(){Id = 8}, new XClass(){Id = 7}};

    var trueData = (from data in x
                   orderby !numbersToFilterBy.Contains(data.Id), data.Id
                    select data).ToList();

    foreach(var item in trueData){
        Console.WriteLine(item.Id);
  }
}

public class XClass{
    public int Id{get;set;}
  }
}

What is the explanation as to why this happens?

The OrderBy method will sort items in ascending order by default . Now, given that the numeric representation of a boolean is:

  • false = 0
  • true = 1

false values will naturally come first. If you want to reverse the order just use the descending keyword:

var trueData = (from data in x
               orderby numbersToFilterBy.Contains(data.Id) descending, data.Id
                select data).ToList();

Basically, false is earlier than true ... think of them as false=0, true=1. This is in-keeping with the documentation for bool.CompareTo(bool) .

If you want to prioritize "true" values to the start, just use OrderByDescending instead.

Ordering isn't about priority – it's about ordinal value . You're doing an ascending order against a boolean value, and false has a lower ordinal value than true in that context.

Let me explain this with an example of a List<bool> . Consider the following snippet:

List<bool> BoolList = new List<bool>() { true, false, false, true };
var opList = BoolList.OrderBy(x => x).ToList();

finally the opList will have the values as false , false , true , true which means false come first when we apply OrderBy over a list of boolean values. This is because false is consider as 0 and true will be 1 .

In your case the list is first sorted as 5,1,9,3,4,2,6,8,7 based on the orderby !numbersToFilterBy.Contains(data.Id) then by data.Id will gives you the exact result as 5, 1, 2, 3, 4, 6, 7, 8, 9 .

If you remove the ! from the OrderBy it gives you the first sort result like 1,9,3,4,2,6,8,7,5 since the condition is true for 5 hence it will come last in the ordering.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM