Ordem Linq por booleano

111

Eu tenho uma consulta linq que desejo ordenar por f.bar, que é uma string, mas também quero ordená-la por f.foo, que é um campo booleano, primeiro. Como a consulta abaixo.

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

Embora compile, não funciona como esperado. Ele apenas ordena por f.bar ignorando o campo booleano.

Estou sendo idiota, eu sei, mas o que preciso fazer para obter esse comportamento?

obrigado

mat-mcloughlin
fonte

Respostas:

175

Isso deve funcionar bem - deve ordenar as entidades com um falsevalor foo primeiro, depois aquelas com um truevalor foo.

Isso certamente funciona no LINQ to Objects - qual provedor LINQ você está realmente usando?

Aqui está um LINQ to Objects exemplo que faz o trabalho:

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
fonte
51
Falha épica ... acabei de perceber que era devido a um bug que significava que f.foo sempre foi falso ... tão envergonhado
mat-mcloughlin
5
Correto, false(0) vem antes de true(1) em ordem de classificação crescente (padrão).
silkfire,
Como faço para agrupar a Coluna1 pelo número de verdadeiros na Coluna 2?
Oracular Man
2
@OracularMan: Eu sugiro que você faça uma nova pergunta com um exemplo detalhado.
Jon Skeet
1
@Sipo: Asdata.OrderBy(d => d.x).ThenBy(d => d.y)
Jon Skeet
119

Só queria fazer isso e parece algo sem ordem implícita. Fiz o seguinte para ser mais explícito:

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

para classificar algo verdadeiro para falso.

JonnyRaa
fonte
27
Eu meio que gosto disso mais do que da forma embutida. Principalmente porque, mesmo que haja uma ordem implícita para verdadeiro / falso, não é realmente óbvio para quem não o fez antes. Portanto, alguém que não sabe olhar para o código no futuro pode pensar que classifica de verdadeiro para falso, quando na verdade classifica de falso para verdadeiro ... pelo menos com esta solução, o código torna dolorosamente óbvio de que maneira você pretende classificar.
Robert Noack
2
sim, eu gosto disso no código! Se você tiver que ir para o msdn ou stackoverflow para ler a documentação para entender o código, então não é um ótimo código na minha opinião
JonnyRaa
2
Cheira a números mágicos para mim. Estou errado em presumir que todo programador deve inerentemente saber muito bem que um booleano truesignifica a single bit set to 1? Para mim, a verdade true > falseé tão óbvia quanto pode ser.
Mels
4
@Mels não números mágicos. Valores explícitos usados ​​para classificação e classificação apenas. Os valores podem ser 42 e 69, a questão é que o leitor do código sabe que um deles é menor, pois será o primeiro. O leitor do código provavelmente não sabe de que maneira um OrderBy colocará os bools - será verdadeiro primeiro ou falso será o primeiro. true > falsenão é universalmente conhecido, ao passo que 1 > 0é.
Dan F
9
Observe que .OrderBy(e => e.SomeFlag == true)seria equivalente a .OrderBy(e => e.SomeFlag)enquanto .OrderBy(e => e.SomeFlag ? 0 : 1)é equivalente a .OrderByDescending(e => e.SomeFlag). As duas primeiras classificam falso antes de verdadeiro, as outras duas classificam verdadeiro antes de falso.
EriF89
0

Tente seguir o código se obtiver a lista orderby true.

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

Para ser mais explícito sobre a ordem que está sendo usada.

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
fonte