Pedidos seletivos com LINQ, pedidos parciais
Pergunta
Digamos que eu tenho uma lista de objetos:
var items = new {
new { Order = 0 },
new { Order = 1 },
new { Order = -1 },
new { Order = 3 },
new { Order = 2 },
new { Order = -1 }
};
Eu preciso encomendá -lo para que itens com Order > -1
estar no topo da lista ordenada por ordem ascendente e itens restantes com Order == -1
estavam seguindo -os.
Existe uma maneira mais elegante de fazer isso do que usar Conact()
e Where()
cláusulas:
var orderedItems = items.Where(x => x.Order > -1).OrderBy(x => x.Order)
.Conact(items.Where(x => x.Order == -1);
Para que depois de classificar esta lista seria:
var items = new {
new { Order = 0 },
new { Order = 1 },
new { Order = 2 },
new { Order = 3 },
new { Order = -1 },
new { Order = -1 }
};
Também items
A lista no cenário real já é um complexo IQueryable<T>
objeto. É por isso que estou tentando encontrar a maneira mais ideal de fazer pedidos tão seletivos.
Solução
Você pode tentar isso - produz o resultado que você espera:
items.OrderBy(x.Order => x.Order == -1).ThenBy(x.Order => x.Order);
Outras dicas
Como Mike mencionou, no seu exemplo, funcionaria automaticamente, mas dizia que queríamos obter todos os elementos -1 primeiro e depois classificar os elementos restantes em uma ordem decrescente. Isso pode ser feito usando um belo truque. Você pode usar várias chaves ao solicitar elementos. A primeira chave pode ser um valor booleano que será false
para todos -1 valores (então eles serão os primeiros) e true
Para todos os outros valores (para que eles não sejam reordenados). A segunda chave pode ser o que você deseja solicitar os elementos restantes. Por exemplo:
var nums = new int[] { -1, 4, 2, 3, -1, 4, 7 };
var q = from n in nums
orderby n != -1, n descending
select n;
Primeiro produzirá todos os valores para os quais n != -1
é false
e então todos os elementos encomendados usando n descending
Então você receberá:
-1, -1, 7, 4, 4, 3, 2
Isso funciona em geral quando você precisa lidar com alguns elementos, especialmente no pedido - você só precisa fornecer as chaves de pedidos certas.
Se você pedir por ascensão, -1 já deve estar na parte superior da lista, porque é o menor valor.
No entanto, de maneira mais geral, se você ainda quisesse aplicar a classificação diferente em subconjuntos dos dados, acho que não haveria uma maneira mais elegante, porque é exatamente isso que você está fazendo e o sindicato é logicamente preciso. Você está tentando puxar dois subconjuntos separados dos dados, classificá -los de maneira diferente e, em seguida, mesclá -los, que é uma das coisas para as quais a união deve ser usada.
Também um comparador personalizado aqui se você quiser que -1 apareça primeiro, mas o resto é descendente , mas de alguma forma eu acho mais elegante :) note que é feito para ints
class Comparer : IComparer<int>
{
public int Compare(int x, int y)
{
if (x == -1 || y == -1) return x - y;
return y - x;
}
}
OrderBy(x => x.Order < 0 ? int.MaxValue : x.Order)
ou se você precisar solicitar os valores negativos em ordem decrescente
OrderBy(x => x.Order < 0 ? (long)int.MaxValue - x.Order : (long)x.Order)
Use um comparador personalizado Para definir o pedido que você deseja.
public class MyComparer : IComparer<int>
{
public int Compare(int a, int b)
{
if ((a < 0) && (b >= 0))
{
return 1;
}
if ((a >= 0) && (b < 0))
{
return -1;
}
return int.Compare(a, b);
}
}
Então você poderia fazer:
var orderedItems = items.OrderBy(x => x.Order, new MyComparer());