2016-12-01 2 views
0

入れ子のforループを宣言スタイルに変換するにはどうすればよいですか?入れ子の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は何も返さないので、コードはコンパイルされません。 'List'に' void'を代入することはできません。 – Servy

+2

私はその本がIEnumerable(おそらくbook.Pagesではなく、page.Lines?)であるとは思うが、Robがそれを釘付けにしたことは確かだ。しかし、ネストされたSelectMany()コールはこれを行うLinqの方法です –

+2

@Rob私はあなたがコメントとして多くのコメントを投稿し、人々があなたの答えを盗み、なぜあなたの獲得したアップボートを手に入れませんか? – 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私は可読性を向上させるためにそれを行いました。入れ子にされた「選択」は非常に難しいです。この例では、3つのレベルを深くネストする必要があります。それは実際には理解しすぎるほどです。しかし、私はこのソリューションが同じ出力を生むことに同意します。 –

関連する問題