2010-03-08 8 views
9

Dato un elenco di elementi in questo modo:utilizzando LINQ per selezionare un intervallo di membri in un elenco

int[] ia = new int[] { -4, 10, 11, 12, 13, -1, 9, 8, 7, 6, 5, 4, -2, 
         6, 15, 32, -5, 6, 19, 22 }; 

C'è un modo semplice in LINQ per fare qualcosa sulla falsariga di "Seleziona gli elementi dalla - 1 fino al prossimo numero negativo (o l'elenco esaurisce) "? Un risultato positivo per -1 sarebbe (-1, 9, 8, 7, 6, 5, 4). Usare -2 darebbe il risultato (-2, 6, 15, 32).

Non un problema di compiti a casa. Sto solo guardando un'implementazione usando uno bool, un ciclo for e uno if chiedendo se c'è un modo più pulito per farlo.

risposta

11

Dai un'occhiata al metodo di estensione Linq TakeWhile. Prende elementi dall'elenco finché la condizione è vera, salta il resto.

Esempio:

int[] ia = new int[] { -4, 10, 11, 12, 13, -1, 9, 8, 7, 6, 5, 4, -2, 
         6, 15, 32, -5, 6, 19, 22 }; 

var result = ia 
      .SkipWhile(i => i != -1) 
      .Skip(1) 
      .TakeWhile(i => i >= 0); 

Nota Skip (1) dopo la SkipWhile. SkipWhile salta tutto fino a, ma non incluso l'elemento corrispondente. TakeWhile then Takes items, fino a ma non incluso l'elemento corrispondente. Poiché -1 non è maggiore o uguale a zero, ottieni un risultato vuoto.

+0

ho cercato 'SkipWhile' /' TakeWhile' e ha fatto lo stesso errore di Anders. Non mi è venuto in mente di saltare l'uno. Andando a lasciare questo aperto un po 'più a lungo per vedere quale varietà cade. –

+0

Questa soluzione non includerà il primo '-1' nel set di risultati. –

+0

Non è vero. Ma dal momento che il -1 era l'indicatore per l'inizio del set - è l'unico valore conosciuto - può essere inserito nei risultati. –

5

Aggiornato

Questa volta ho provato il codice ... Utilizzando la forma a due parametri di TakeWhile possiamo costringerlo ad accettare il primo elemento (j == 0) anche quando il banco di prova per i non è soddisfatto .

ia.SkipWhile(i => i != -1).TakeWhile((i, j) => i >= 0 || j == 0)

TakeWhile(Func<int, int, bool>) richiede una funzione/lambda che accetta due parametri. Il primo è il valore da testare, il secondo è l'indice dell'elemento.

+0

Pensato a questo e questo dà un risultato vuoto. –

+0

Hai ragione che TakeWhile (i => i> = 0) restituisce un risultato vuoto. Vedi il mio sforzo aggiornato (e testato) sopra. –

+0

Questo dà i risultati corretti ora. –

0

Dev'essere Linq? È possibile utilizzare i metodi Estensioni per ottenere una soluzione più pulita.

int[] ia = new int[] { -4, 10, 11, 12, 13, -1, 9, 8, 7, 6, 5, 4, -2, 
         6, 15, 32, -5, 6, 19, 22 }; 

// Call the Extension method 
int[] results = ia.SelectRangeLoop(-2); 

// Print Results 
for (int i = 0; i < results.Length; i++) 
{ 
    Console.Write(" {0} ", results[i]); 
} 

Il metodo per SelectRangeLoop è riportato di seguito.

public static int[] SelectRangeLoop(this int[] value, int startNumber) 
{ 
    List<int> results = new List<int>(); 

    bool inNegative = false; 

    for (int i = 0; i < value.Length; i++) 
    { 
     if (value[i] == startNumber) 
     { 
      inNegative = true; 

      results.Add(value[i]); 

      continue; 
     } 

     if (inNegative && value[i] < 0) 
     { 
      break; 
     } 

     if (inNegative) 
     { 
      results.Add(value[i]); 
     } 
    } 

    return results.ToArray(); 
} 
+0

Non deve essere Linq ma sembrava una scelta ovvia .. Hai semplicemente spostato il 'for',' if' e 'bool' da qualche altra parte. Se lo stavo facendo molto e non avessi un'opzione più concisa, allora potrebbe essere un utile metodo di estensione. –

0
var first = ia.Select((i, index) => new {i, index}).Where((i, index) => i.i == x).First(); 
var ind = first.index; 
var second = ia.SkipWhile((i, index) => index <= ind).TakeWhile(i => i > 0); 
var ints = new[]{first.i}.Union(second); 
+0

{7, -1, 4, -1, 5} dà {-1, 4, -1, 5} invece di {-1, 4} con quella soluzione. –

Problemi correlati