Combine neighboring parts of an array based on a condition I have written this code which takes a one dimensional array, for example:

{"abc","ade","sss","fgw","asd","lka","o"}

and turns it into an array of arrays, combining the elements which do not meet the condition.

For the condition m=&gt;!m.Contains("a") for example, the output will be:

{{"abc","ade"},{"sss"},{"fgw"},{"asd","lka"},{"o"}}

The code works, but i suspect there is a linq way to do it, and refrain from using temporary variables that i dislike.

    public static string[][] combineBy(this string[] inp,Func&lt;string,bool&gt; f)
    {
        List&lt;string[]&gt; holdElements = new List&lt;string[]&gt;();
        while (inp.Length!=0)
        {
            if (f.Invoke(inp[0]))
            {
                holdElements.Add(new string[] { inp[0] });
                inp = inp.Skip(1).ToArray();
            }
            else
            {
                var toAdd = inp.TakeWhile(n =&gt; !f.Invoke(n));
                holdElements.Add(toAdd.ToArray());
                inp = inp.Skip(toAdd.Count()).ToArray();
            }
        }
        return holdElements.ToArray();
    }
Some general remarks about your code:


combineBy use PascalCase for method names
f it's not a good parameter name, if it's a condition function they are usualy named predicate
predicate.Invoke(...) - you can call it directly with predicate(...)
values.TakeWhile(n =&gt; !predicate(n)) - do not enumerate it twice, call ToArray and use it in the subsequent lines
if you like it the LINQ way you can write values.Any() instead of values.Length != 0 and values.First() instead of values[0] also this new string[] { inp[0] } could be turned into values.Take(1).ToArray()
don't use abbreviations for variables like inp or f, use full names like values and predicate


x

public static string[][] CombineBy(this string[] values, Func&lt;string, bool&gt; predicate)
{
    var result = new List&lt;string[]&gt;();
    while (values.Any())
    {
        if (predicate(values.First()))
        {
            result.Add(values.Take(1).ToArray());
            values = values.Skip(1).ToArray();
        }
        else
        {
            var toAdd = values.TakeWhile(n =&gt; !predicate(n)).ToArray();
            result .Add(toAdd);
            values = values.Skip(toAdd.Length).ToArray();
        }
    }
    return result.ToArray();
}




Unfortuantely your code doesn't seem to work and returns invalid results. This should do:

public static List&lt;List&lt;string&gt;&gt; CombineBy(this string[] values, Func&lt;string, bool&gt; predicate)
{
    var result = new List&lt;List&lt;string&gt;&gt;();

    foreach (var value in values)
    {
        if (predicate(value))
        {
            if (!result.Any() || !predicate(result.Last().Last()))
            {
                result.Add(new List&lt;string&gt;());
            }
            result.Last().Add(value);
        }
        else
        {
            result.Add(new List&lt;string&gt; { value });
        }
    }

    return result;
}


or even without loops:

public static List&lt;List&lt;string&gt;&gt; CombineBy3(this string[] values, Func&lt;string, bool&gt; predicate)
{
    var result = values.Aggregate(new List&lt;List&lt;string&gt;&gt;(), (current, next) =&gt;
    {
        if (predicate(next))
        {
            if (!current.Any() || !predicate(current.Last().Last()))
            {
                current.Add(new List&lt;string&gt;());
            }
            current.Last().Add(next);
        }
        else
        {
            current.Add(new List&lt;string&gt; { next });
        }
        return current;
    });
    return result;
}