Win Man Win Man - 1 year ago 55
C# Question

Converting a nested for loop to declarative in c#

How would convert a nested for loop to declarative style?

Sample code:

List<String> words = new List<String>();
Books.ForEach(book => book.ForEach(page =>
page.ForEach(line =>words.Add(CreateWord(book, page, line)))));

Answer Source

If you wish to improve readability, then you could approach step-by-step. First expand each book entry into a sequence of (book, page) pairs. Then each pair convert to a triplet (book, page, line) and convert that to strings using the CreateWords method.

Code is telling more than words, and this is how it looks:

List<string> words = Books
    .SelectMany(book => book.Pages.Select(page => new
            Book = book,
            Page = page
    .SelectMany(pair => pair.Page.Lines.SelectMany(line =>
        new CreateWords(book, page, line));

This might not be the most readable piece of LINQ code. But it often goes like that. LINQ tends to produce compact but ugly mapping code.

On a related note, I wonder what is the purpose of CreateWords method? If it only returns a sequence of strings, then entire adventure with book, page and line is not required. If I'm right, you might change CreateWords to only receive a single string representing the line - it does not require book or page objects at all. In that case, query would be simplified:

List<string> words = Books
    .SelectMany(book => book.Pages)
    .SelectMany(page => page.Lines)
    .SelectMany(line => CreateWords(line));