Как я могу обрезать список <string>, чтобы предыдущие и последующие пустые строки были удалены? - PullRequest
6 голосов
/ 24 февраля 2010

Какой самый простой способ сделать это?

Результаты должны быть:

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

Код:

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

Ответы [ 8 ]

9 голосов
/ 24 февраля 2010

Хорошо, теперь я понимаю желаемые результаты:

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

Обратите внимание, что не не изменяет существующий список - он возвращает новый список с требуемым содержимым. Непонятно, какое именно поведение вы хотите, учитывая, что вы дали методу тип возвращаемого значения, но ваш пример вызывает его без использования результата. Лично я предпочитаю методы без побочных эффектов, хотя, возможно, стоит сменить название:)

6 голосов
/ 24 февраля 2010

Что по этому поводу:

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

Обратите внимание, что подпись изменилась из вашего примера (тип возвращаемого значения void).

5 голосов
/ 24 февраля 2010

Попробуйте это:

public static List<string> TrimList(this List<string> list)  
    {  
        return list.SkipWhile(l => String.IsNullOrEmpty(l)).Reverse().SkipWhile(l => String.IsNullOrEmpty(l)).Reverse();
    } 
1 голос
/ 27 июня 2014

Старый вопрос Я знаю, но вот метод расширения, который будет обрезать объекты в начале и в конце коллекции на основе логического делегата с использованием 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();
    }
}

Пример для вашего случая:

lines.Trim(line => string.IsNullOrEmpty(line)); 
0 голосов
/ 24 февраля 2010
    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));
0 голосов
/ 24 февраля 2010

Иногда старый добрый foreach превосходит linq с точки зрения читабельности и производительности:

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 голосов
/ 24 февраля 2010

Нет ничего встроенного, чтобы сделать что-то подобное. Вы можете проверить элементы от начала и до конца и удалить пустые строки. Чтобы свести к минимуму операции со списком (повторное использование RemoveAt для удаления первого элемента довольно неэффективно), сначала подсчитайте количество удаляемых элементов, а затем используйте метод RemoveRange, чтобы удалить их все сразу.

Чтобы соответствовать тому, как вы используете метод в коде, расширение должно изменить список, а не возвращать новый список.

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);
}
0 голосов
/ 24 февраля 2010

Если вы хотите удалить пустые строки, вы можете сделать что-то вроде этого ...

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

Обновление: Извините, я только что видел ваши изменения, которые вы хотите оставить внутренние пробелы.

В этом случае я бы просто использовал метод расширения, подобный тому, который вы упомянули выше, поскольку я не думаю, что есть более простой способ сделать это.

...