質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

Q&A

解決済

2回答

1658閲覧

Listや内部クラスを持ったクラスにLinqを使い、条件検索と値の追加(add)をする方法

hiro.888

総合スコア1

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

0グッド

0クリップ

投稿2020/05/23 05:44

編集2020/05/23 05:51

前提・実現したいこと

C#を使った開発をしています。(.NET Framework 4.7.2)

ある多重構造のclassの子classに含まれるListに対して、
値を値を追加しようと思っています。

foreachでは、実現出することが出来たのですが、可能であれば、linqを利用してシンプルなコートに変更しようと思っています。

当方いろいろ試したのですが、うまくデータを書き換えることが出来ず、苦戦しております。
皆様の知恵をお借りできないでしょうか。

linqを使わずに行った場合(現在出来ている)

クラス

C#

1 public class student 2 { 3 public int id; 4 public string name; 5 public List<testResult> testResults = new List<testResult>(); 6 7 } 8 9 public class testResult 10 { 11 public int times; 12 public int score; 13 }

サンプルデータ

C#

1 // サンプルデータを作成 2 static List<student> createSampleData() 3 { 4 var student = new student(); 5 var testResult = new testResult(); 6 var students = new List<student>(); 7 8 //サンプル作成(Aさん) 9 student = new student(); 10 student.id = 1; 11 student.name = "A"; 12 13 //1回目テスト 14 testResult = new testResult(); 15 testResult.times = 1; 16 testResult.score = 30; 17 student.testResults.Add(testResult); 18 19 //2回目テスト 20 testResult = new testResult(); 21 testResult.times = 2; 22 testResult.score = 40; 23 student.testResults.Add(testResult); 24 25 //3回目テスト 26 testResult = new testResult(); 27 testResult.times = 3; 28 testResult.score = 50; 29 student.testResults.Add(testResult); 30 31 students.Add(student); 32 33 //サンプル作成(Bさん) 34 student = new student(); 35 student.id = 2; 36 student.name = "B"; 37 38 //1回目テスト 39 testResult = new testResult(); 40 testResult.times = 1; 41 testResult.score = 90; 42 student.testResults.Add(testResult); 43 44 //2回目テスト 45 testResult = new testResult(); 46 testResult.times = 2; 47 testResult.score = 80; 48 student.testResults.Add(testResult); 49 50 students.Add(student); 51 52 return students; 53 }

実際のロジック

C#

1 static void Main(string[] args) 2 { 3 // サンプルデータ取得 4 var students = createSampleData(); 5 6 //本題 7 //ID:2のBさんの3回目テスト結果(99点)を追加する 8 var testResult = new testResult(); 9 testResult.times = 3; 10 testResult.score = 99; 11 12 //Linqに置き換えたい部分 ↓ 13 foreach (var student in students) 14 { 15 if (student.id == 2) 16 { 17 student.testResults.Add(testResult); 18 } 19 } 20 //Linqに置き換えたい部分 ↑ 21 }

試したこと

C#

1students.Where(student => student.id == 2).

whereを使いBさんの絞り込みまでは出来ているが、この跡list(testResults)にデータを追加(add)する方法が見つからないです。

C#

1students.Where(student => student.id == 2).Select(x => x.testResults = x.testResults.Append(testResult).ToList());

このような形を試してみましたが間違いのようでした。色々と検索をしているのですが、解決策が見いだせず苦戦しております。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/05/23 06:00 編集

foreach でできてるならいいんじゃないかと思いますが、LINQ どうこう言うよりも Dictionary を使ったほうがシンプルになるように思います。 dictionary[2].testResults.Add(new testResult { times = 3, score = 99 });
hiro.888

2020/05/23 06:08 編集

確かにおっしゃる通り、 Dictionary のほうがシンプルになりそうですね。 コメントありがとうございます。 残念ながら、実際のプログラムではすでに稼働しているものであり、また他のソースでも多岐にわたり このクラスを見てるため大幅な変更が難しい状況です。 また、今回質問をするに当たりかなり簡単な構造でサンプルを作成しています。 実際は4階層くらいの入れ子になっておりforeachで回すとスコープの範囲すら分かりにくくなると言った 状態でして、なんとかlinqでスッキリ出来ないかと考えているところでした。
Zuishin

2020/05/23 06:11

多重ループするくらいなら、余計に Dictionary を作るのがいいと思います。クラス全体で使わなくても、リストの作成部分で使い捨てるだけでもかなりパフォーマンスが上がりそうです。
hiro.888

2020/05/23 06:12

そうなんですね。一旦試してみます。ありがとうございます。
hiro.888

2020/05/23 07:58

Zuishinさん dictionaryでの実装がうまくいきました。ありがとうございました。 ただ、後学のため、タイトルの通りLinqでのコーディングも引き続き調査したいと思います。 ご存知の方がいらっしゃればアドバイスをいただければと思います。
hihijiji

2020/05/23 08:58

LINQが使いにくい場面は、LINQを使うべきではない場面です。
guest

回答2

0

ベストアンサー

こんにちは。

質問に対する回答ではないですが、
まず、Linq がやるべきことは、その名前の通り Query であり、「リストに Add する」などの Action に相当する処理は Linq で行うべきではないものと考えます。

この質問に記載された「実際のロジック」からその本来の意図を読み取ると、「students から id == 2 である student を抽出する」と読み替えることができるため、以下のように書くのが良いと思います。
Linq 本来の目的の一つである、処理の意図を明らかにし、不要なループを除去するという目的は達成できています。

csharp

1// id == 2 である student を手に入れる 2var target = students.Single(student => student.id == 2); 3 4// testResult を target に追加 5target.testResults.Add(testResult);

ただし、今回のような用途では、id を元に Dictionary を作った方が良いのは追記修正にもある通りです。

投稿2020/05/23 11:27

tamoto

総合スコア4252

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiro.888

2020/05/24 03:07 編集

ご回答ありがとうございます。 皆さんお答えのようにやはりDictionaryのkeyをうまく使ったほうが良いということですね。 サンプルコードもありがとうございます。 今回はid=ユニークなコードで例を出していたのですが、実際のコードでは、idの部分がユニークではない場合、複合キー(Tupleが必要?)の場合、id==2 ではなく、id <= 2 のような範囲で使用することもあり、書き方の幅を広げたいと思っての質問でした。 大変参考になりました。
TN8001

2020/05/24 03:05

ldを重複させるつもりはないということでしょうが、元ロジックと等価ではない点は注意が必要です。
guest

0

私は好きではありませんが、手軽にやるならこうとか?

cs

1students.Where(s => s.id == 2).ToList().ForEach(s => s.testResults.Add(testResult));

投稿2020/05/23 10:04

編集2023/07/22 04:42
TN8001

総合スコア9862

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiro.888

2020/05/24 03:03

ご回答ありがとうございます。 サンプルコードありがとうございます。 かけないことはないということですね。 ただ、あまり適切ではない書き方ということも、勉強になりました。 大変参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問