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

26,706

Solution 1

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();

Solution 2

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.

Solution 3

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.

Solution 4

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.

Share:
26,706
DotNet NF
Author by

DotNet NF

.Net Developer

Updated on July 09, 2022

Comments

  • DotNet NF
    DotNet NF over 1 year

    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?

  • Chris
    Chris over 7 years
    In c# booleans don't have a numeric representation. They aren't numbers behind the scenes that we pretend are booleans, they are just booleans. That having been said the logic may well help people remember how the ordering works (and may well be why the design of .net is this way) but it is worth remembering that there is no numeric representation of a bool in .net.
  • Chris
    Chris over 7 years
    As I said on another answer false is never considered to be 0 and true 1. It has the same results as if they were but its actually just that they defined an ordering on the two boolean values. It might be nitpicking but suggesting that the framework might be converting bools to integers is misleading and no simpler than the true statement that they just defined an ordering. It might help people remember the ordering if they are used to languages that do have conversion between bools and numeric values of course.
  • Sebastian Redl
    Sebastian Redl over 7 years
    @Chris But there is a numeric result if you cast the boolean to an integer. Which is still more than some other languages have.
  • Chris
    Chris over 7 years
    The line int test = (int)true; throws a compiler exception of Cannot convert type 'bool' to 'int'. How are you casting without an error?
  • Sebastian Siemens
    Sebastian Siemens over 7 years
    @Chris bool.CompareTo(bool) returns integer which will then be used when ordering
  • Chris
    Chris over 7 years
    @SebastianSchulz: That's not the same as the boolean being an integer. All CompareTo methods return an integer. Its just how comparisons work. See msdn.microsoft.com/en-us/library/… for more details but basically 0 menas they are equal, negative means the instance comes before the parameter and positive means the instance comes after the parameter. The result of CompareTo indicates the order, it is not used when ordering (ie it doesn't sort by the result of CompareTo which is what it sounds like you may be suggesting).
  • Jean Hominal
    Jean Hominal over 7 years
    @Chris Convert.ToInt32(Boolean) converts false to 0 and true to 1.
  • Chris
    Chris over 7 years
    @JeanHominal: This is true but the code in that method is completely independant of the code in Boolean.CompareTo. It doesn't convert to an integer to do a comparison, it doesn't even care that you could think of a boolean in terms of an integer. It just defines that false comes before true when ordering ascending - no numbers are involved anywhere.
  • camerondm9
    camerondm9 over 7 years
    @Chris At least internally, false == 0 and true == 1. See referencesource.microsoft.com/#mscorlib/system/…
  • Chris
    Chris over 7 years
    @camerondm9: As I seem to be repeating that is different from booleans being the same as integers. That internal number is a) an implementation detail and thus irrelevant to what a boolean actually is b) Only actually used for when you are converting to other datatypes or for the GetHashCode implementation. However much you can draw parallels between boolean values and numbers there is no language level link between them.