入れ子のforループを宣言スタイルに変換するにはどうすればよいですか?入れ子のforループをcで宣言的に変換する#
サンプルコード:
List<String> words = new List<String>();
Books.ForEach(book => book.ForEach(page =>
page.ForEach(line =>words.Add(CreateWord(book, page, line)))));
入れ子のforループを宣言スタイルに変換するにはどうすればよいですか?入れ子のforループをcで宣言的に変換する#
サンプルコード:
List<String> words = new List<String>();
Books.ForEach(book => book.ForEach(page =>
page.ForEach(line =>words.Add(CreateWord(book, page, line)))));
あなたが読みやすさを改善したい場合、あなたはステップバイステップに近づくことができました。まず、各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));
匿名のタイプは必要ありません。お互いの内部を選択することで、選択肢へのフルアクセスが可能になります。 – Dispersia
これは匿名型の使用方法を説明していますが、RobのオリジナルのSelectMany()呼び出しはネストされているため、ラッピングオブジェクトを使わずにブックとページを参照できます。私はおそらくより簡潔なネストされたバージョンに行くだろうが、あなたは明確に概念を説明すると思います。 –
@Dispersia私は可読性を向上させるためにそれを行いました。入れ子にされた「選択」は非常に難しいです。この例では、3つのレベルを深くネストする必要があります。それは実際には理解しすぎるほどです。しかし、私はこのソリューションが同じ出力を生むことに同意します。 –
ForEachは何も返さないので、コードはコンパイルされません。 'List'に' void'を代入することはできません。 – Servy
私はその本がIEnumerable(おそらくbook.Pagesではなく、page.Lines?)であるとは思うが、Robがそれを釘付けにしたことは確かだ。しかし、ネストされたSelectMany()コールはこれを行うLinqの方法です –
@Rob私はあなたがコメントとして多くのコメントを投稿し、人々があなたの答えを盗み、なぜあなたの獲得したアップボートを手に入れませんか? – Dispersia