2

Say I have a List<string> listOfStrings and I want to divide this list into two lists based on some predicate. E.g., the first list should contain all strings that start with a letter, and second is a list of strings that don't.

Now I would do this like this:

var firstList = listOfStrings.Where(str => predicate(str));
var secondList = listOfStrings.Where(str => !predicate(str));

Is there a better way of doing this in one line?

eddyP23
  • 6,420
  • 7
  • 49
  • 87

4 Answers4

9

You can use Linq's GroupBy():

var splitted = listOfStrings.GroupBy(s => Char.IsLetter(s[0]));

And with your predicate, it would be:

Func<string, bool> predicate;

var splitted = listOfStrings.GroupBy(predicate);

Usage:

The easiest way would be to convert the grouped data into a Dictionary<bool, IEnumerable<string>>, when the key is a bool that denotes whether the items in it start with a letter:

var splitted = list.GroupBy(x => Char.IsLetter(x[0]))
                   .ToDictionary(x => x.Key, z => z.ToArray());  

var startWithLetter = splitted[true];
var dontStartWithLetter = splitted[false];

Of course, there are many ways to massage the data into your desired structure, but the above is pretty concise in my opinion.

See MSDN

haim770
  • 48,394
  • 7
  • 105
  • 133
4

Kotlin has partition function (sources). C# version:

var (first, second) = list.Partition(x => x.IsTrue);

Extension:

public static (IEnumerable<T> first, IEnumerable<T> second) Partition<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
    var lookup = list.ToLookup(predicate);
    return (lookup[true], lookup[false]);
}

Could be more convenient to return List<T>, or to use GroupBy or something else, depending on use case.

thomius
  • 784
  • 2
  • 9
  • 21
1

You can use 'GroupBy' or 'ToLookup', based on what you will be doing with the results. Check also lookup vs. groupby

Fortega
  • 19,463
  • 14
  • 75
  • 113
0

I would do something like this:

class Program
{
    static void Main(string[] args)
    {
        Func<string, bool> startsWithA = s => s[0] == 'a';

        List<string> listOfStrings = new List<string>()
        {
            "abc",
            "acb",
            "bac",
            "bca",
            "cab",
            "cba"
        };

        Dictionary<bool, List<string>> dictionaryOfListsOfStrings = listOfStrings.GroupBy(startsWithA).ToDictionary(x => x.Key, x => x.ToList());
    }
}
Marco Salerno
  • 5,131
  • 2
  • 12
  • 32