开发者

How can I trim a List<string> so preceding and succeeding blank lines are removed?

开发者 https://www.devze.com 2022-12-20 22:30 出处:网络
What is the easiest way to do this? The results should be: 1: one 2: two 3: 4: 5: five Code: using System; using System.Collections.Generic;

What is the easiest way to do this?

The results should be:

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

Code:

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 Helper开发者_如何学Cs
    {
        public static List<string> TrimList(this List<string> list)
        {
            //???
        }
    }
}


Okay, now I understand the desired results:

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

Note that this doesn't change the existing list - it returns a new list with the desired content. It wasn't clear exactly what behaviour you wanted, given that you've given the method a return type, but your sample calls it without using the result. Personally I prefer non-side-effecting methods, although it may be worth changing the name :)


What about this:

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

Note that the signature has changed from your example (return type is void).


Try this one:

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


Old Question I know, but here is an extension method that will trim objects from the beginning and end of a collection based on a boolean delegate using 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();
    }
}

Example for your case:

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


If you wanted to remove the empty strings you could do something like this...

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

Update: Sorry just seen your edit that you want internal blanks to remain.

In this case I would just an extension method like the one you mention above as I don't think there is a simpler way of doing it.


There is nothing built in to do something specific like that. You can check the items from the beginning and end and remove the empty strings. To minimise the operations on the list (using RemoveAt repeatedly to remove the first item is rather inefficient), first count the number of items to remove and then use the RemoveRange method to remove them all at once.

To match how you use the method in the code, the extension has to alter the list rather than returning a new list.

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


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


Sometime the good old foreach beats linq both from the readability and performance perspective:

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

精彩评论

暂无评论...
验证码 换一张
取 消