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.

Foi útil?

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());
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top