Ordinamento selettivo con LINQ, ordinamento parziale
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.
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());