Reputation: 193352
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 Helpers
{
public static List<string> TrimList(this List<string> list)
{
//???
}
}
}
Upvotes: 6
Views: 4604
Reputation: 4433
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));
Upvotes: 1
Reputation: 1502216
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 :)
Upvotes: 9
Reputation: 49639
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;
}
}
}
Upvotes: 0
Reputation: 57222
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).
Upvotes: 6
Reputation: 17964
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));
Upvotes: 0
Reputation: 25573
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();
}
Upvotes: 5
Reputation: 700572
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);
}
Upvotes: 0
Reputation: 4892
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.
Upvotes: 0