Linq orden por booleano

111

Tengo una consulta de linq que quiero ordenar por f.bar, que es una cadena, pero también quiero ordenarla por f.foo, que es un campo booleano, primero. Como la consulta a continuación.

(from f in foo
orderby f.foo, f.bar
select f)

Aunque esto se compila, no funciona como se esperaba. Simplemente ordena por f.bar ignorando el campo booleano.

Estoy siendo tonto, lo sé, pero ¿qué debo hacer para tener este comportamiento?

Gracias

mat-mcloughlin
fuente

Respuestas:

175

Eso debería funcionar bien: debería ordenar las entidades con un falsevalor foo primero, luego aquellas con un truevalor foo.

Eso ciertamente funciona en LINQ to Objects: ¿qué proveedor de LINQ está utilizando realmente?

He aquí un ejemplo de LINQ a objetos, que hace el trabajo:

using System;
using System.Linq;

public static class Test
{
    public static void Main()
    {
        var data = new[]
        {
            new { x = false, y = "hello" },
            new { x = true, y = "abc" },
            new { x = false, y = "def" },
            new { x = true, y = "world" }
        };

        var query = from d in data
                    orderby d.x, d.y
                    select d;

        foreach (var result in query)
        {
            Console.WriteLine(result);
        }
    }

}
Jon Skeet
fuente
51
Fallo épico ... me acabo de dar cuenta de que se debía a un error que significaba que f.foo siempre era falso ... tan avergonzado
mat-mcloughlin
5
Correcto, false(0) viene antes de true(1) en orden ascendente (predeterminado).
Silkfire
¿Cómo agrupo la Columna 1 por número de verdadero en la Columna 2?
Oracular Man
2
@OracularMan: Le sugiero que haga una nueva pregunta con un ejemplo detallado.
Jon Skeet
1
@Sipo: Asdata.OrderBy(d => d.x).ThenBy(d => d.y)
Jon Skeet
119

Solo quería hacer esto y parece algo sin un orden implícito. Hice lo siguiente para ser más explícito:

Something.OrderBy(e=>e.SomeFlag ? 0 : 1) 

para ordenar algo verdadero a falso.

JonnyRaa
fuente
27
Me gusta esto más que la forma incorporada. Principalmente porque incluso si hay un orden implícito de verdadero / falso, no es realmente obvio para nadie que no lo haya hecho antes. Entonces, alguien que no sepa mirar el código en el futuro podría pensar que se clasifica de verdadero a falso, cuando en realidad se clasifica de falso a verdadero ... al menos con esta solución, el código hace que sea dolorosamente obvio de qué manera pretende ordenar.
Robert Noack
2
¡Sí, me gusta eso en código! Si tiene que ir a msdn o stackoverflow para leer la documentación y comprender el código, en mi opinión
JonnyRaa
2
A mí me huele a números mágicos. ¿Me equivoco al suponer que todo programador debería saber inherentemente muy bien lo que truesignifica un booleano a single bit set to 1? Para mí, la verdad true > falsees tan obvia como puede ser.
Mels
4
@Mels no son números mágicos. Los valores explícitos se utilizan solo para ordenar y ordenar. Los valores pueden ser 42 y 69, el punto es que el lector del código sabe que uno de ellos es menor, por lo tanto será el primero. El lector del código probablemente no sepa de qué manera un OrderBy pondrá los bools: será verdadero primero o falso primero. true > falseno es universalmente conocido, mientras 1 > 0que sí.
Dan F
9
Tenga en cuenta que .OrderBy(e => e.SomeFlag == true)sería equivalente a .OrderBy(e => e.SomeFlag)mientras que .OrderBy(e => e.SomeFlag ? 0 : 1)es el equivalente de .OrderByDescending(e => e.SomeFlag). Los dos primeros clasifican falso antes que verdadero, los otros dos clasifican verdadero antes que falso.
EriF89
0

Intente seguir el código si obtiene la lista orderby true.

db.member.where(x=>x.id==memberId).OrderBy(x=>!x.IsPrimary?1:0).ToList();
Muhammad Armaghan
fuente
0

Para ser más explícito sobre el orden que se utiliza.

Something.OrderBy(e => e.SomeFlag, new BooleanComparer());

public class BooleanComparer : IComparer<bool>
{
    public int Compare(bool x, bool y)
    {
        int p = x ? 1 : 0;
        int q = y ? 1 : 0;
        return p - q; 
    }
}
Wouter
fuente