5

给定 aList<string>我需要删除列表开头和结尾的所有空行

注意:我认为空行是没有内容的行,但可能包含空格和制表符。这是检查一行是否为空的方法:

    private bool HasContent(string line)
    {
        if (string.IsNullOrEmpty(line))
            return false;

        foreach (char c in line)
        {
            if (c != ' ' && c != '\t')
                return true;
        }

        return false;
    }

你会建议什么高效且可读的代码来做到这一点?

确认示例

[" ", " ", " ", " ", "A", "B", " ", "C", " ", "D", " ", " ", " "]

应该通过删除开头结尾的所有空行来修剪这样的列表,以得到以下结果:

["A", "B", " ", "C", " ", "D"]
4

10 回答 10

8
var results = textLines1.SkipWhile(e => !HasContent(e))
                        .Reverse()
                        .SkipWhile(e => !HasContent(e))
                        .Reverse()
                        .ToList();

这个怎么运作?跳过列表中的所有空行,反转它并执行相同操作(实际上跳过列表后面的所有空行)。在另一个反向之后,您会以正确的顺序获得正确的结果。

如果列表真的很大while,出于性能考虑,您可以考虑使用标准循环和列表索引,但对于正常数据而言,回归应该无关紧要。

于 2013-03-12T09:56:36.980 回答
4

首先,有一个内置方法可以检查:String.IsNullOrWhiteSpace();

ColinE 提供的答案不符合要求,因为它删除了所有空行,而不仅仅是在开头或结尾处。

我认为您需要构建自己的解决方案:

int start = 0, end = sourceList.Count - 1;

while (start < end && String.IsNullOrWhiteSpace(sourceList[start])) start++;
while (end >= start && String.IsNullOrWhiteSpace(sourceList[end])) end--;

return sourceList.Skip(start).Take(end - start + 1);
于 2013-03-12T10:01:09.287 回答
2

使用 Linq,您可以执行以下操作:

IEnumerable<string> list  = sourceList.SkipWhile(source => !HasContent(source))
                                      .TakeWhile(source => HasContent(source));

这会“跳过”字符串,直到找到有内容的字符串,然后“获取”所有字符串,直到找到没有内容的字符串。

尽管正如@MarcinJuraszek 指出的那样,这将在没有内容的第一行之后停止,而不是删除列表末尾的那些。

为此,您可以使用以下内容:

IEnumerable<string> list  = sourceList.SkipWhile(source => !HasContent(source))
                                      .Reverse()
                                      .SkipWhile(source => !HasContent(source))
                                      .Reverse();

有点令人费解,但应该可以解决问题。

于 2013-03-12T09:54:33.383 回答
2

检查我刚才做的这个扩展方法:

public static class ListExtensions
{
    public static List<string> TrimList(this List<string> list)
    {
        int listCount = list.Count;
        List<string> listCopy = list.ToList();
        List<string> result = list.ToList();

        // This will encapsulate removing an item and the condition to remove it.
        // If it removes the whole item at some index, it return TRUE.
        Func<int, bool> RemoveItemAt = index =>
        {
            bool removed = false;

            if (string.IsNullOrEmpty(listCopy[index]) || string.IsNullOrWhiteSpace(listCopy[index]))
            {
                result.Remove(result.First(item => item == listCopy[index]));
                removed = true;
            }

            return removed;
        };

        // This will encapsulate the iteration over the list and the search of 
        // empty strings in the given list
        Action RemoveWhiteSpaceItems = () =>
        {
            int listIndex = 0;

            while (listIndex < listCount && RemoveItemAt(listIndex))
            {
                listIndex++;
            }
        };

        // Removing the empty lines at the beginning of the list
        RemoveWhiteSpaceItems();

        // Now reversing the list in order to remove the 
        // empty lines at the end of the given list
        listCopy.Reverse();
        result.Reverse();

        // Removing the empty lines at the end of the list
        RemoveWhiteSpaceItems();

        // Reversing again in order to recover the right list order.
        result.Reverse();

        return result;
    }
}

...及其用法:

List<string> list = new List<string> { "\t", " ", "    ", "a", "b", "\t", "         ", " " };

// The TrimList() extension method will return a new list without
// the empty items at the beginning and the end of the sample list!
List<string> trimmedList = list.TrimList();
于 2013-03-12T10:13:04.880 回答
2

这种方法修改了原始 List<string>对象,而不是创建具有所需属性的新对象:

static void TrimEmptyLines(List<string> listToModify)
{
  if (listToModify == null)
    throw new ArgumentNullException();

  int last = listToModify.FindLastIndex(HasContent);
  if (last == -1)
  {
    // no lines have content
    listToModify.Clear();
    return;
  }
  int count = listToModify.Count - last - 1;
  if (count > 0)
    listToModify.RemoveRange(last + 1, count);

  int first = listToModify.FindIndex(HasContent);
  if (first > 0)
    listToModify.RemoveRange(0, first);
}

在这段代码中,HasContent是来自原始问题的方法。可以将匿名函数(如 lambda)用于委托。

于 2013-03-12T12:16:47.770 回答
1

下面的代码可以满足您的需要:

List<string> lines = new List<string> {"   \n\t", " ", "aaa", "  \t\n", "bb", "\n", " "};
IEnumerable<string> filtered = lines.SkipWhile(String.IsNullOrWhiteSpace).Reverse().SkipWhile(String.IsNullOrWhiteSpace).Reverse();

它将列表反转两次,因此如果性能是关键,它可能不是理想的解决方案。

于 2013-03-12T09:58:28.733 回答
-1

您可以使用 isnullorwhitespace 来检查:请参见下面的示例。

        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.RemoveAll(string.IsNullOrWhiteSpace);
于 2013-03-12T10:06:25.120 回答
-1
List<string> name = new List<string>();
name.Add("              ");
name.Add("rajesh");
name.Add("raj");
name.Add("rakesh");
name.Add("              ");
for (int i = 0; i < name.Count(); i++)
{
  if (string.IsNullOrWhiteSpace(Convert.ToString(name[i])))
  {
    name.RemoveAt(i);
  }
}
于 2013-03-12T10:09:28.007 回答
-2

关于形成您的代码,我猜您的行既不包含空格也不包含制表符,因此您可以foreach

if(line.Contains(' ') || line.Contains('\t'))
   return false;
return true;
于 2013-03-12T09:54:38.857 回答
-2
List<string> name = new List<string>();
name.Add("              ");
name.Add("rajesh");
name.Add("raj");
name.Add("rakesh");
name.Add("              ");

name.RemoveAt(0);
name.RemoveAt(name.Count() - 1);
于 2013-03-12T10:06:02.347 回答