Question: I've to do a generic method `Classify<T>` that, given a sequence of elements of type `T` and an arbitrary number of predicates, returns an array of `n+1` lists (where `n` is the number of the predicates). More precisely, if the element satisfies the first predicate then it is added to the first list. If not, then if the element satisfies the second predicate it is added to the second list, etc. If none of the predicates can be applied to one element, then that element is added to the last list (the n+1 th).

I managed to do that with the following code. Is there any way to do it better, maybe with Linq?

```
public List<T>[] Classify<T>(IEnumerable<T> sequence, params Predicate<T>[] predicates)
{
    var result = new List<T>[predicates.Length+1];
    var counter = 0;    
    foreach (var elem in sequence)      
    {
        var valid = false;
        foreach (var predicate in predicates) 
        {
            if(result[counter]==null)
                result[counter] = new List<T>();
            if (predicate(elem) && valid==false)
            {
                var partition = result[counter];
                partition.Add(elem);
                valid = true;
            }
            counter++;
        }
        if (!valid)     
        {
            if (result[counter] == null)
                result[counter] = new List<T>();
            result[counter].Add(elem);
        }
        counter=0;
    }
    return result;
}

```

Answer: 
```
public List<T>[] Classify<T>(IEnumerable<T> sequence, params Predicate<T>[] predicates)
{
    var result = new List<T>[predicates.Length + 1];
    // It's clearer to create elements of the array explicitly
    for (int i = 0; i < result.Length; i++)
        result[i] = new List<T>();

    foreach (var elem in sequence)
    {
        var index = predicates.TakeWhile(p => !p(elem))
                              .Count();

        result[index].Add(elem);
    }
}

```

There is a few LINQ methods to get an index, f.e. `Select((i, e) => ...)`. If the list of unsatisfied elements was the first (0th), I would use `Select`. But since it is the last, `TakeWhile` gives the shorter code.
There are many ways to strike the balance between LINQ and straight procedural code; the [answer by Mark](https://codereview.stackexchange.com/a/77887/7328) IMO strikes a very good balance between being succinct and easily understandable.

That said you can do this without any procedural code (just LINQ methods) and have the body of the classification method be a single expression. Extra care must be taken so that if there are bins which end up being empty of items the result still includes empty lists in the appropriate indexes ([david's answer](https://codereview.stackexchange.com/a/77885/7328) does not do this and as a result has a bug).

Here's a correct solution with pure LINQ, which I have to admit is more useful as an intellectual exercise rather than as a practical approach:

```
public List<T>[] Classify<T>(IEnumerable<T> sequence, params Predicate<T>[] predicates)
{
    return Enumerable
               .Range(0, predicates.Length + 1)
               .GroupJoin(
                   sequence.GroupBy(item => predicates.TakeWhile(p => !p(item)).Count()),
                   i => i,
                   g => g.Key,
                   (i, g) => g.SelectMany(g2 => g2).ToList()
               )
               .ToArray();
}

```