Domanda

Diciamo che ho un elenco di oggetti:

var items = new {
    new { Order = 0 },
    new { Order = 1 },
    new { Order = -1 },
    new { Order = 3 },
    new { Order = 2 },
    new { Order = -1 }
};

Devo ordinarlo in modo che gli articoli con Order > -1 essere in cima all'elenco ordinato in ordine crescente e gli elementi rimanenti con Order == -1 li stavano seguendo.

Esiste un modo più elegante per farlo rispetto all'utilizzo Conact() E Where() clausole:

var orderedItems = items.Where(x => x.Order > -1).OrderBy(x => x.Order)
                   .Conact(items.Where(x => x.Order == -1);

In modo che dopo aver ordinato questo elenco sarebbe simile a:

var items = new {
    new { Order = 0 },
    new { Order = 1 },
    new { Order = 2 },
    new { Order = 3 },
    new { Order = -1 },
    new { Order = -1 }
};

Anche items l'elenco nello scenario reale è già complesso IQueryable<T> oggetto.Ecco perché sto cercando di trovare il modo più ottimale per eseguire un ordinamento così selettivo.

È stato utile?

Soluzione

Si potrebbe provare questo - produce il risultato che ci si aspetta:

items.OrderBy(x.Order => x.Order == -1).ThenBy(x.Order => x.Order);

Altri suggerimenti

Come Mike accennato, nel tuo esempio, che avrebbe funzionato automaticamente, ma dire che abbiamo voluto ottenere tutti -1 primi elementi e gli elementi quindi ordinare rimanenti in ordine decrescente. Questo può essere fatto utilizzando un bel trucco. È possibile utilizzare più chiavi al momento dell'ordine elementi. La prima chiave può essere un valore booleano che verrà false per tutti i valori -1 (in modo che sarà prima) e true per tutti gli altri valori (in modo non verranno riordinati). La seconda chiave può essere quello che vuoi ordinare gli elementi rimanenti. Ad esempio:

var nums = new int[] { -1, 4, 2, 3, -1, 4, 7 };
var q = from n in nums
        orderby n != -1, n descending
        select n;

E 'in primo luogo produrre tutti i valori per i quali è n != -1 false e quindi tutti gli elementi ordinato utilizzando n descending così avrai:

-1, -1, 7, 4, 4, 3, 2

Questo funziona in generale quando è necessario gestire alcuni elementi in particolare nel l'ordinamento - è sufficiente per fornire la giusta ordinando i tasti

.

Se si ordina da ascendente, -1 dovrebbe già essere in cima alla lista, perché è il valore più piccolo.

Tuttavia, più in generale, se ancora voluto applicare l'ordinamento diverso per sottoinsiemi di dati, non credo che ci sarebbe un modo più elegante, perché questo è esattamente quello che stai facendo e l'unione è logicamente accurate. Si sta cercando di tirare due sottoinsieme separato dei dati fuori, ordinarli in modo diverso, e quindi unire insieme, che è una delle cose che quello che l'unione che deve essere utilizzato per la.

Anche un operatore di confronto personalizzato qui se si vuole -1 ad apparire prima, ma il resto di essere decrescente , ma in qualche modo lo trovo più elegante :) Nota che è fatto per interi

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)

o se è necessario ordinare i valori negativi in ​​ordine decrescente

OrderBy(x => x.Order < 0 ? (long)int.MaxValue - x.Order : (long)x.Order)

di confronto personalizzato per definire l'ordine che si desidera.

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

Poi si potrebbe fare:

var orderedItems = items.OrderBy(x => x.Order, new MyComparer());
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top