【问题标题】:How can I trim a List<string> so preceding and succeeding blank lines are removed?如何修剪 List<string> 以便删除前后的空行?
【发布时间】:2010-02-24 10:28:30
【问题描述】:

最简单的方法是什么?

结果应该是:

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

【问题讨论】:

    标签: c# generics string trim


    【解决方案1】:

    好的,现在我明白了想要的结果:

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

    请注意,此不会更改现有列表 - 它会返回包含所需内容的新列表。鉴于您已经为该方法提供了返回类型,但您的示例在不使用结果的情况下调用它,因此尚不清楚您想要什么行为。我个人更喜欢无副作用的方法,尽管更改名称可能值得:)

    【讨论】:

    • 使用 string.IsNullOrEmpty 比检查字符串长度更安全 我不是要教我的祖母吸鸡蛋,但是。 . .奶奶在这里打了个小洞。 . .
    • @Binary Worrier:是的,你可以。这取决于 - 包含空引用的列表是否代表错误(在这种情况下,例外是合适的)?我怀疑爱德华很乐意自己解决这个问题——尽管我会进行编辑以使其更清晰。 @jk:我不久前修复了这个问题:)
    • 这是真的,我们的 API 被许多不同的客户端应用程序调用,有时我们得到空字符串,有时我们得到空值。如果框架没有提供 string.IsNullOrEmpty,我们会推出自己的 :)
    【解决方案2】:

    这个呢:

        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)。

    【讨论】:

    • 这很简单,但效率很低。此外,如果列表只有空字符串,它会抛出 IndexOutOfRangeException。
    • Ick - 为什么是“0 != list.Count”而不是“list.Count != 0”?我们没有使用 C/C++ :)
    • @Jon Skeet:感谢您的评论,但为时已晚,“0 !=”在我的手指中是硬连线的 :)
    • 现在它不会抛出异常,但它仍然效率低下......;)
    【解决方案3】:

    试试这个:

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

    【讨论】:

      【解决方案4】:

      我知道的老问题,但这里有一个扩展方法,它将使用 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)); 
      

      【讨论】:

        【解决方案5】:

        如果你想删除空字符串,你可以这样做......

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

        更新:抱歉刚刚看到您希望保留内部空白的编辑。

        在这种情况下,我只会使用您上面提到的扩展方法,因为我认为没有更简单的方法。

        【讨论】:

          【解决方案6】:

          没有内置的东西可以做这样的特定事情。您可以从头到尾检查项目并删除空字符串。为了尽量减少对列表的操作(重复使用 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);
          }
          

          【讨论】:

            【解决方案7】:
                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));
            

            【讨论】:

              【解决方案8】:

              有时,从可读性和性能角度来看,旧的 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;
                      }
                  }
              }
              

              【讨论】:

              • 就性能可读性而言,我不能说我喜欢这样。我同意 LINQ 不一定是这里的答案,但使用 FindIndex、FindLastIndex 和 GetRange(根据我和 Carra 的答案)对我来说似乎更易读、更简单......
              猜你喜欢
              • 2011-05-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-04-19
              • 1970-01-01
              相关资源
              最近更新 更多