2016-12-01 76 views
0

如何将嵌套for循环转换为声明风格?将c嵌套for循环转换为声明c#

示例代码:

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

'ForEach'不返回任何东西,所以你的代码不会编译;你不能将'void'分配给'List'。 – Servy

+2

虽然我怀疑这本书是IEnumerable(也许它相当book.Pages和page.Lines?),但我确信Rob已经钉了它。但是,嵌套的SelectMany()调用将是Linq的方式来做到这一点 –

+2

@Rob我看到你张贴答案作为评论很多,人们只是窃取你的答案,为什么不获得你赚的upvotes? – Dispersia

回答

1

如果你想提高可读性,那么你可以接近一步一步的。首先将每个book条目展开为一系列(书,页)对。然后每一对转换为一个三元组(书,页面,行)并使用CreateWords方法将其转换为字符串。

代码告诉多字,这是它的外观:

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)); 

这可能不是最可读的一块LINQ代码。但它往往是这样的。 LINQ倾向于生成紧凑但难看的映射代码。

在相关说明中,我想知道CreateWords方法的用途是什么?如果它只返回一串字符串,那么不需要书,页和线的整个冒险。如果我是对的,你可能会改变CreateWords只接收表示该行的单个字符串 - 它根本不需要书或页面对象。在这种情况下,查询将被简化:

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

你不需要匿名类型。通过在彼此内部进行选择,您可以完全访问所有选择。 – Dispersia

+0

虽然这解释了使用匿名类型,并且可能(更好或更糟)稍微冗长一点,但Rob的原始SelectMany()调用是嵌套的,因此可以在没有包装对象的情况下引用书和页面。我可能会选择更简洁的嵌套版本,但是确实认为你清楚地解释了这个概念。 –

+0

@Dispersia我这样做是为了提高可读性。嵌套'选择'很难遵循。在这个例子中,我们必须深入嵌套三个层次,这实在太难理解了。但我同意该解决方案会产生相同的输出。 –