Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove empty lines at the beginning and at the end of a List<string>?

Tags:

string

c#

.net

Given a List<string> I need to remove all the empty lines at the beginning and at the end of the list.

NOTE: I consider an empty line a line that has no content, but may contain whitespaces and tabs. This is the method to check if a line is empty:

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

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

        return false;
    }

What efficient and readable code would you suggest to do that?

Confirmed example

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

Such a list should be trimmed, by removing all empty lines at the beginning and the end to the following result:

["A", "B", " ", "C", " ", "D"]
like image 243
Daniel Peñalba Avatar asked Mar 12 '13 09:03

Daniel Peñalba


4 Answers

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

How it works? Skips all empty lines at from of the list, reverse it and do the same (what actually skips all empty lines from back of the list). After another reverse you're getting proper results in right order.

If list is really huge you can consider using standard while loops and list indexing because of performance considerations, but for normal data impart of reversion shouldn't really matter.

like image 63
MarcinJuraszek Avatar answered Nov 14 '22 01:11

MarcinJuraszek


First off, there is a built in method that checks this: String.IsNullOrWhiteSpace();

The answer ColinE provides does not meet the requirement since it removes all lines that are empty, not just at the beginning or end.

I think you need to build your own solution:

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);
like image 4
Bas Avatar answered Nov 14 '22 03:11

Bas


Using Linq, you could perform the following:

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

This 'skips' strings until it finds one with content, then 'takes' all the strings until one without content is found.

Although as @MarcinJuraszek points out, this will stop after the first line that does not have content, rather than removing those at the end of the list.

To do that, you could use the following:

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

A little bit convoluted, but should do the trick.

like image 2
ColinE Avatar answered Nov 14 '22 01:11

ColinE


Check this extension method I did just now:

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

...and its usage:

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();
like image 2
Matías Fidemraizer Avatar answered Nov 14 '22 01:11

Matías Fidemraizer