2010-02-24 8 views
6

¿Cuál es la forma más fácil de hacer esto?¿Cómo puedo recortar una lista <string> para que se eliminen las líneas en blanco precedentes y siguientes?

Los resultados deben ser:

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

Código:

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) 
     { 
      //??? 
     } 
    } 
} 

Respuesta

6

Qué tal esto:

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

Tenga en cuenta que la firma ha cambiado de su ejemplo (tipo de retorno es nulo) .

+1

Eso es fácil pero ineficiente. Además, arroja una excepción IndexOutOfRangeException si la lista solo tiene cadenas vacías. – Guffa

+0

@Guffa: tienes razón, gracias, actualicé el código. –

+4

Ick: por qué "0! = List.Count" en lugar de "list.Count! = 0"? No estamos usando C/C++ :) –

0

Si quisiera eliminar las cadenas vacías que podría hacer algo como esto ...

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

Actualización: Lo sentimos, hemos visto su edición que desea espacios en blanco internos para permanecer.

En este caso, yo solo usaría un método de extensión como el que mencionas anteriormente ya que no creo que haya una forma más sencilla de hacerlo.

9

Vale, ahora entiendo los resultados deseados:

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

Tenga en cuenta que este no cambio de la lista existente - que devuelve una nueva lista con el contenido deseado. No estaba claro exactamente qué comportamiento quería, dado que le ha dado al método un tipo de devolución, pero su muestra lo llama sin usar el resultado. Personalmente prefiero no de lado a efectuar métodos, aunque puede ser vale la pena cambiar el nombre :)

+0

más seguro de usar cuerdas.IsNullOrEmpty en lugar de verificar longitud de cadena No quiero enseñarle a mi abuela a chupar huevos, pero. . . La abuela hace un pequeño agujero aquí y. . . –

+0

Bueno, esta es básicamente mi respuesta ... – Carra

+0

@Binary Worrier: Sí, podrías. Depende - ¿la lista que contiene una referencia nula representa un error (en cuyo caso una excepción es apropiada) o no? Sospecho que Edward está feliz de arreglarlo él mismo, aunque editaré para hacerlo más claro. @jk: lo arreglé hace un tiempo :) –

0

No hay nada incorporado para hacer algo específico como eso. Puede verificar los elementos desde el principio hasta el final y eliminar las cadenas vacías. Para minimizar las operaciones en la lista (usar RemoveAt repetidamente para eliminar el primer elemento es bastante ineficiente), primero cuente el número de elementos para eliminar y luego use el método RemoveRange para eliminarlos todos a la vez.

Para que coincida con la forma de utilizar el método en el código, la extensión debe modificar la lista en lugar de devolver una nueva lista.

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

Prueba con esto:

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

En algún momento el buen viejo foreach late LINQ tanto desde la legibilidad y el rendimiento perspectiva:

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

No puedo decir que me gusta en términos de rendimiento * o * legibilidad. Estoy de acuerdo con que LINQ no es necesariamente la respuesta aquí, pero el uso de FindIndex, FindLastIndex y GetRange (como el mío y la respuesta de Carra) me parece más legible y más simple ... –

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

vieja pregunta que sé, pero aquí es un método de extensión que recortará objetos desde el principio y el final de una colección en función de un delegado booleano utilizando 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(); 
    } 
} 

Ejemplo para su caso:

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