🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

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

LINQ

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

Q&A

解決済

2回答

3352閲覧

独自クラスを持つリスト同士のプロパティを比較し一致した値を代入する処理

HAL-

総合スコア2

C#

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

LINQ

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

0グッド

0クリップ

投稿2021/03/30 10:38

編集2021/03/30 10:55

独自クラスを持つリストが2つあり、2つのリストにあるCDプロパティを比較して
CDに一致するNameプロパティを上書きする処理をエレガントに書く方法を教えて下さい。

以下のプログラムではuser3のCDとowner3のCDが初めに一致するためnameプロパティがowner3に書き換えられます。
※owner99も一致しますが、CDはユニークな想定なため初めに一致したCDを返す想定です。

class Person { public int CD; public string Name; } List<Person> userPersonList = new List<Person>(){ new Person(){ CD = 1,Name = "user1"}, new Person(){ CD = 2,Name = "user2"}, new Person(){ CD = 3,Name = "user3"} }; List<Person> ownerPersonList = new List<Person>(){ new Person(){ CD = 4,Name = "owner1"}, new Person(){ CD = 5,Name = "owner2"}, new Person(){ CD = 6,Name = "owner3"}, new Person(){ CD = 3,Name = "owner3"} new Person(){ CD = 3,Name = "owner99"} }; foreach(var userPerson in userPersonList){ foreach(var ownerPerson in ownerPersonList){ if(userPerson.CD == ownerPerson.CD){ userPerson.Name = ownerPerson.Name; break; } } }

以下は試してみた代入部分のLINQ構文です。

foreach(var result in userPersonList.Where(x => ownerPersonList.Select(y => y.CD).Contains(x.CD))){ result.Name = ownerPersonList.Where(x => x.CD == result.CD).Select(x => x.Name).FirstOrDefault(); }

新規に拡張メソッド作成する方法は使わないようにお願いします。
C#のバージョンは6.0です。

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

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

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

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

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

guest

回答2

0

もうベストアンサーもついてるので意味はないかもしれませんがあくまで書き換え処理に絞って考えると下記のようにDictionaryを使用する方法なんかもありではないでしょうか?

C#

1var ownerPersons = ownerPersonList 2 .GroupBy(x => x.CD) 3 .Select(x => x.First()) 4 .ToDictionary(x => x.CD); 5 6foreach (var userPerson in userPersonList) { 7 8 if (ownerPersons.TryGetValue(userPerson.CD, out var ownerPerson)) { 9 userPerson.Name = ownerPerson.Name; 10 } 11 12}

投稿2021/03/31 01:31

dekaaki

総合スコア292

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

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

HAL-

2021/03/31 13:55 編集

ご回答ありがとうございます。 Dictionaryへ変換しtryGetで比較しそのまま代入する方法は思いつきませんでした。 私の書いた方法よりかなりスマートだと思います! 質問させて頂いた処理はプログラムを書いていくとわりとぶつかる処理だと思うので拡張メソッドを使用しない書き換え処理を行う場合に、また悩んだ際はこちらのコードを参考にさせていただきたいと思います。
guest

0

ベストアンサー

Person に IEqutable<Person> を実装して

C#

1public class Person : IEquatable<Person> 2{ 3 public int CD; 4 public string Name; 5 6 public bool Equals(Person other) 7 { 8 if (other is null) 9 return false; 10 11 return CD == other.CD && Name == other.Name; 12 } 13 14 public override bool Equals(object obj) => Equals(obj as Person); 15 public override int GetHashCode() => (CD, Name).GetHashCode(); 16}

Enumerable.Intersect メソッドで userPersonList の積集合を取得することで下記のように記述できます。エレガントかはわかりません。

C#

1var intersect = userPersonList.Intersect(ownerPersonList); 2foreach(var user in intersect){ 3 var owner = ownerPersonList.FirstOrDefault(x => x.CD == user.CD); 4 user.Name = owner?.Name; 5}

IEqutable<TSource> を実装したくない場合は IEqualityComparer<TSource> を使っても実現できます。

IEqualityComparer を使う場合

C#

1public class Person 2{ 3 public int CD; 4 public string Name; 5} 6 7public class PersonComparer : IEqualityComparer<Person> 8{ 9 public bool Equals(Person x, Person y) 10 { 11 if (Object.ReferenceEquals(x, y)) return true; 12 13 if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 14 return false; 15 16 return x.CD == y.CD && x.Name == y.Name; 17 } 18 19 public int GetHashCode(Person person) 20 { 21 if (Object.ReferenceEquals(person, null)) return 0; 22 23 int hashPersonName = person.Name == null ? 0 : person.Name.GetHashCode(); 24 int hashPersonCode = person.CD.GetHashCode(); 25 26 return hashPersonName ^ hashPersonCode ; 27 } 28}

C#

1var intersect = userPersonList.Intersect(ownerPersonList, new PersonComparer()); 2foreach(var user in intersect){ 3 var owner = ownerPersonList.FirstOrDefault(x => x.CD == user.CD); 4 user.Name = owner?.Name; 5}

投稿2021/03/30 11:33

編集2021/03/30 11:56
BluOxy

総合スコア2663

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

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

HAL-

2021/03/30 11:46

早速のご回答ありがとうございます。 IEqutable<Person> の実装は理想的なのですが共通クラスへの実装を想定しているため、overrideするのは難しそうです。 IEqualityComparer でも実装できるということで存じ上げなかったので調べて挑戦してみます! 難しい場合はご提案頂いたunionを用いた実装しようと思います。
BluOxy

2021/04/01 02:47 編集

Union メソッドを用いることと IEqutable<Person> を実装することは、別の手法ではありません。 Union メソッドで使用する比較条件を指定する手段の1つが IEqutable<Person> を実装することです。
BluOxy

2021/03/30 12:01

もしくは IEqualityComparer<Person> を実装したクラスを定義しても Union メソッドで使用する比較条件を指定することもできます。代わりに Union メソッドの引数には IEqualityComparer<Person> のインスタンスを渡す必要があります。 リファレンスのサンプルを真似しただけですが、IEqualityComparer<Person> を使用したコードも追記しました。
HAL-

2021/03/31 13:42

ご指摘の通りUnionメソッドを用いた手法は勘違いしていました・・・。 リファレンスを参照し上記内容を参考に無事実装することができました。 ご丁寧に指導していただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問