Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

split a list using linq

Tags:

c#

I've the following code:

  var e = someList.GetEnumerator();
  var a = new List<Foo>();
  var b = new List<Foo>();
  while(e.MoveNext())  {
     if(CheckCondition(e.Current)) {
         b.Add(e.Current);
         break;
     }
     a.Add(e.Current);
 }

while(e.MoveNext())
  b.Add(e.Current)

This looks ugly. Basically, iterate through a list and add elements to one list until some condition kicks in, and add the rest to another list.

Is there a better way e.g. using linq ? CheckCondition() is expensive, and the lists can be huge so I'd prefer to not do anything that iterates the lists twice.

like image 603
Anonym Avatar asked Jan 06 '11 01:01

Anonym


2 Answers

Here's a solution that's going to enumerate the list twice, but it won't check the condition the second time, so it should be faster:

var a = someList.TakeWhile(x => !CheckCondition(x)).ToList();
var b = someList.Skip(a.Count).ToList();

If someList implements IList<T>, each item will actually be enumerated only once, so there won't be any penalty.
I thought Skip was optimized for the case of IList<T>, but apparently it's not... However you could easily implement your own Skip method that uses this optimization (see Jon Skeet's article about this)

It would actually be more elegant if there was a TakeUntil method... we can easily create it:

public static IEnumerable<TSource> TakeUntil<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    foreach(var item in source)
    {
        if (predicate(item))
            break;
        yield return item;
    }
}

With this method, the code becomes:

var a = someList.TakeUntil(CheckCondition).ToList();
var b = someList.Skip(a.Count).ToList();
like image 188
Thomas Levesque Avatar answered Oct 25 '22 18:10

Thomas Levesque


I didn't want to change Ani's answer, but here's a slight simplification.

var listToBeAdded = a;
foreach (var item in someList)
{
    if (listToBeAdded == a && CheckCondition(item))
        listToBeAdded = b;

    listToBeAdded.Add(item);
}
like image 22
Gabe Avatar answered Oct 25 '22 17:10

Gabe