2010-02-24 2 views
6

Qual è il modo più semplice per farlo?Come posso tagliare un elenco <string> in modo che le righe bianche precedenti e successive siano rimosse?

I risultati dovrebbero essere:

1: one 
2: two 
3: 
4: 
5: five 

Codice:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace TestLines8833 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<string> lines = new List<string>(); 
      lines.Add(""); 
      lines.Add("one"); 
      lines.Add("two"); 
      lines.Add(""); 
      lines.Add(""); 
      lines.Add("five"); 
      lines.Add(""); 
      lines.Add(""); 

      lines.TrimList(); 
     } 
    } 

    public static class Helpers 
    { 
     public static List<string> TrimList(this List<string> list) 
     { 
      //??? 
     } 
    } 
} 

risposta

6

Che dire di questo:

public static void TrimList(this List<string> list) { 
     while (0 != list.Count && string.IsNullOrEmpty(list[0])) { 
      list.RemoveAt(0); 
     } 
     while (0 != list.Count && string.IsNullOrEmpty(list[list.Count - 1])) { 
      list.RemoveAt(list.Count - 1); 
     } 
    } 

Nota che la firma è cambiato dal vostro esempio (tipo restituito è void) .

+1

È semplice ma inefficiente. Inoltre, genera una IndexOutOfRangeException se l'elenco contiene solo stringhe vuote. – Guffa

+0

@Guffa: hai ragione, grazie, ho aggiornato il codice. –

+4

Ick - perché "0! = List.Count" invece di "list.Count! = 0"? Non stiamo usando C/C++ :) –

0

Se si voleva rimuovere le corde vuote che si potrebbe fare qualcosa di simile ...

lines = lines.Where(s => ! string.IsNullOrEmpty(s)).ToList(); 

Aggiornamento: Scusa appena visto la modifica che desideri spazi vuoti interni per rimanere.

In questo caso, vorrei solo un metodo di estensione come quello che hai menzionato sopra perché non penso che ci sia un modo più semplice di farlo.

9

Okay, ora ho capito i risultati desiderati:

public static class Helpers 
{ 
    // Adjust this to use trimming, avoid nullity etc if you you want 
    private static readonly Predicate<string> 
     NonBlankLinePredicate = x => x.Length != 0; 

    public static List<string> TrimList(this List<string> list) 
    { 
     int start = list.FindIndex(NonBlankLinePredicate); 
     int end = list.FindLastIndex(NonBlankLinePredicate); 

     // Either start and end are both -1, or neither is 
     if (start == -1) 
     { 
      return new List<string>(); 
     } 
     return list.GetRange(start, end - start + 1); 
    } 
} 

Si noti che questo non cambiamento dell'elenco esistente - restituisce una nuova lista con il contenuto desiderato. Non era chiaro esattamente quale comportamento volevi, dato che hai dato al metodo un tipo di ritorno, ma il tuo campione lo chiama senza usare il risultato. Personalmente preferisco non side-effettuando i metodi, anche se può valere la pena di cambiare il nome :)

+0

più sicuro da usare stringa.IsNullOrEmpty piuttosto che controllare la lunghezza della stringa Non intendo insegnare a mia nonna a succhiare le uova, ma. . . La nonnina fa un piccolo buco qui e. . . –

+0

Beh, questa è praticamente la mia risposta ... – Carra

+0

@ Writer Binary: Sì, è possibile. Dipende - la lista che contiene un riferimento null rappresenta un bug (nel qual caso un'eccezione è appropriata) o no? Sospetto che Edward sia abbastanza felice da sistemarlo da solo, anche se modificherò per renderlo più chiaro. @jk: l'ho risolto qualche tempo fa :) –

0

Non c'è nulla di integrato nel fare qualcosa di specifico. È possibile controllare gli elementi dall'inizio e alla fine e rimuovere le stringhe vuote. Per ridurre al minimo le operazioni nell'elenco (utilizzando RemoveAt ripetutamente per rimuovere il primo elemento è piuttosto inefficiente), prima conta il numero di elementi da rimuovere e quindi utilizza il metodo RemoveRange per rimuoverli tutti in una volta.

Per corrispondere a come si utilizza il metodo nel codice, l'estensione deve modificare l'elenco anziché restituire un nuovo elenco.

public static void TrimList(this List<string> list) { 
    int cnt = 0; 
    while (cnt < list.Count && list[cnt].Length == 0) cnt++; 
    if (cnt > 0) list.RemoveRange(0, cnt); 
    cnt = 0; 
    while (cnt < list.Count - 1 && list[list.Count - cnt - 1].Length == 0) cnt++; 
    if (cnt > 0) list.RemoveRange(list.Count - cnt, cnt); 
} 
5

Provate questo:

public static List<string> TrimList(this List<string> list) 
    { 
     return list.SkipWhile(l => String.IsNullOrEmpty(l)).Reverse().SkipWhile(l => String.IsNullOrEmpty(l)).Reverse(); 
    } 
0

volte il buon vecchio foreach batte LINQ sia dal leggibilità e le prestazioni prospettiva:

public static List<string> TrimList(this List<string> list) 
{ 
    list.TrimListStart(); 
    vat l = list.Reverse().ToList(); 
    l.TrimListStart(); 
    return l; 
} 

public void TrimListStart(this List<string> list) 
{ 
    foreach(var s in new List(list)) 
    { 
     if(string.string.IsNullOrWhiteSpace(s)) 
     { 
      list.Remove(s); 
     } 
     else 
     { 
      break; 
     } 
    } 
} 
+0

Non posso dire che mi piaccia in termini di rendimento * o * leggibilità. Sono d'accordo che LINQ non è necessariamente la risposta qui, ma usando FindIndex, FindLastIndex e GetRange (come per la mia e la risposta di Carra) sembra sia più leggibile e più semplice per me ... –

0
int start = stringList.FindIndex((i => i.Trim() != "")); 
    int end = stringList.FindLastIndex((i => i.Trim() != "")); 
    List<string> range = new List<string>(); 
    if(start != -1 && end != -1) 
     range = stringList.GetRange(start, (end - start + 1)); 
1

Vecchio Question Lo so, ma qui è un metodo di estensione che consente di tagliare gli oggetti dall'inizio e alla fine di una raccolta in base a un delegato booleano utilizzando Linq.

public static class IEnumerableExtensions 
{ 
    public static IEnumerable<T> Trim<T>(this IEnumerable<T> collection, Func<T, bool> trimCondition) 
    { 
      return collection.SkipWhile(trimCondition).Reverse().SkipWhile(trimCondition).Reverse(); 
    } 
} 

Esempio per il vostro caso:

lines.Trim(line => string.IsNullOrEmpty(line));