2014-05-10 10 views
8

Sto cercando di ottenere un elenco di stringhe ordinate in modo tale che le più lunghe siano alle estremità dell'elenco e quelle più corte si trovino nel mezzo. Per esempio:LINQ ordine non lineare per lunghezza delle stringhe

A 
BB 
CCC 
DDDD 
EEEEE 
FFFFFF 

otterrebbe ordinato come:

FFFFFF 
DDDD 
BB 
A 
CCC 
EEEEE 

EDIT: Per chiarire, mi è stato specificamente alla ricerca di un'implementazione di LINQ per ottenere i risultati desiderati perché non ero sicuro di come/se fosse possibile usare LINQ.

risposta

7

Non chiedere come e perché ... ^^

Ok, prima che mi dimentichi come funziona, ecco qui.

Un elenco con 6 articoli, ad esempio, deve essere riordinato a questo; la stringa più lunga è l'indice 5, il più breve nell'indice 0 della lista preselezionata.

5 3 1 0 2 4 

Si inizia con Enumerable.Range(0, length) cedevole

0 1 2 3 4 5 

poi si applica i => length - 1 - 2 * i cedevole

5 3 1 -1 -3 -5 

e abbiamo la parte non negativo corretta. Ora nota che i >> 31 è uno spostamento aritmetico a sinistra e copierà il bit di segno in tutti i bit. Pertanto i numeri non negativi producono 0 mentre i numeri negativi danno -1. Che a sua volta significa sottrarre i >> 31 non cambierà numeri non negativi ma aggiungere 1 ai numeri negativi cedevole

5 3 1 0 -2 -4 

e ora finalmente applicare Math.Abs() e ricevere

5 3 1 0 2 4 

che è il risultato desiderato. Funziona allo stesso modo per gli elenchi di lunghezza dispari.

+0

Risposta impressionante. – chad

+0

Ma nulla di ciò che si vuole inserire nel codice di produzione. O forse solo con un * lotto * di commenti. –

10

Si potrebbe creare due gruppi ordinati, poi ordinare il primo gruppo discendente (già fatto) e il secondo ascendente gruppo:

var strings = new List<string> { 
     "A", 
     "BB", 
     "CCC", 
     "DDDD", 
     "EEEEE", 
     "FFFFFF"}; 
var two = strings.OrderByDescending(str => str.Length) 
     .Select((str, index) => new { str, index }) 
     .GroupBy(x => x.index % 2) 
     .ToList(); // two groups, ToList to prevent double execution in following query 
List<string> ordered = two.First() 
    .Concat(two.Last().OrderBy(x => x.str.Length)) 
    .Select(x => x.str) 
    .ToList(); 

Risultato:

[0] "FFFFFF" string 
[1] "DDDD"  string 
[2] "BB"  string 
[3] "A"   string 
[4] "CCC"  string 
[5] "EEEEE"  string 
0

Solo un'altra opzione, che trovo più leggibile e facile da seguire: Hai una lista ordinata:

var strings = new List<string> { 
     "A", 
     "BB", 
     "CCC", 
     "DDDD", 
     "EEEEE", 
     "FFFFFF"}; 

Creare un nuovo elenco e semplicemente si alternano in cui si aggiungono elementi ::

var new_list = new List<string>(); // This will hold your results 
bool start = true;     // Insert at head or tail 

foreach (var s in strings) 
{ 
    if (start) 
     new_list.Insert(0,s); 
    else   
     new_list.Add(s); 

    start = !start;    // Flip the insert location 
} 

dolce e semplice :)

per quanto riguarda Daniel Bruckner commento, se avete a cuore che le stringhe vengono Per prima cosa, puoi anche modificare la condizione di partenza in:

// This will make sure the longest strings is first 
bool start= strings.Count()%2 == 1; 
+0

Questo sarà un po 'diverso da uno per gli elenchi di lunghezza pari - la stringa più lunga sarà nell'ultima posizione. Correzione: 'var start = strings.Count% 2 == 1;' –

+0

Ha detto che "i più lunghi sono alle due estremità dell'elenco", quindi funziona ancora nel mio libro :). Volevo evitare di calcolare dove mettere la stringa e KISS. – Noctis

+0

Punto giusto. Alla fine ho rinunciato a capire come implementarlo nel codice di produzione. –

Problemi correlati