AppleクラスとOrangeクラスがあり、それぞれリンゴとミカンの性質(重さ、値段、色、出荷日…)をプロパティで保持しているとします。
二つのクラスは型も名称も同じプロパティを多く持っていますが、全プロパティが共通しているわけではありません。
List<Apple>とList<Orange>を生成し、
AppleとOrangeの「重さ」と「値段」の二つが同じ要素は削除したいです。
・重さ、値段はint型です
・AppleとOrangeどちらかを残すかという優先度はありません。
・Aplle、Orangeともに自クラス内では重さと値段で一意となっています。
思いついたのはList<Apple>から重さと値段の組み合わせを抽出して、
List<Orange>に一致するものがあれば消すという方法です。
しかし、List<AppleAndOrange>のような、
両方の型を入れられるようなListを作って、
重さと値段が一致する要素は初めの要素だけ残すやり方ができれば
よりスマートだなと思っています。
このようなやり方はできますでしょうか?
また、他により良いアイデアがあればご教示いただきたいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/04/27 01:46
回答3件
0
こんな構成のクラスを作っておいて
C#
1interface IFruits 2{ 3 decimal Weight { get; set; } 4 decimal Price { get; set; } 5} 6 7class EquatableFruits : IFruits, IEquatable<EquatableFruits> 8{ 9 public decimal Weight { get; set; } 10 public decimal Price { get; set; } 11 12 public override int GetHashCode() 13 { 14 return Weight.GetHashCode() ^ Price.GetHashCode(); 15 } 16 17 public virtual bool Equals(EquatableFruits other) 18 { 19 return 20 this.Price == other.Price 21 && 22 this.Weight == other.Weight; 23 } 24} 25 26class Orange : EquatableFruits 27{ 28 public bool IsNoSeed { get; set; } 29} 30 31class Apple : EquatableFruits 32{ 33 public bool WithHoney { get; set; } 34}
こんな感じで使います。
C#
1var fruits = new List<EquatableFruits>(); 2 3var apples = new List<Apple> 4{ 5 new Apple 6 { 7 Price = 100, 8 Weight = 200, 9 WithHoney = true 10 } 11}; 12 13var oranges = new List<Orange> 14{ 15 new Orange 16 { 17 Price = 100, 18 IsNoSeed = true, 19 Weight = 200 20 } 21}; 22 23fruits.AddRange(apples); 24fruits.AddRange(oranges); 25 26var result = fruits.Distinct().ToList();
--- 追記 --
あるいは基底クラス(EquatableFruits)を用いずにIFruitsの比較クラスを用意して
C#
1class FruitsEqualtyComparer : IEqualityComparer<IFruits> 2{ 3 public bool Equals(IFruits x, IFruits y) 4 { 5 return x.Price == y.Price && x.Weight == y.Weight; 6 } 7 8 public int GetHashCode(IFruits obj) 9 { 10 return obj.Price.GetHashCode() ^ obj.Weight.GetHashCode(); 11 } 12}
C#
1var fruits2 = new List<IFruits>(); 2fruits2.AddRange(apples); 3fruits2.AddRange(oranges); 4 5var result2 = fruits.Distinct(new FruitsEqualtyComparer()).ToList();
のほうが汎用的かもしれません。
投稿2019/04/27 01:48
編集2019/04/27 04:58総合スコア4150
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2019/04/27 02:33
2019/04/27 03:11
2019/04/27 16:40
0
ベストアンサー
みなさん Distinct を使われていますが、求められるのは和集合であり、価格と重さの組み合わせはもともとの集合の中では一意ということなので Union を使ってみました。
CustomEqualityComparer は比較用クラスですが、これを作っておけば実際に使用する際にはラムダ式から作成できるので何かと便利です。
LINQ は他にも集合演算ができます。今回は和集合を求める質問でしたが、もしも本来の目的が和集合ではなく差集合または排他的論理和集合であるなら、次の資料をご覧ください。
C#
1using System; 2using System.Collections.Generic; 3using System.Linq; 4 5namespace ConsoleApp1 6{ 7 public class CustomEqualityComparer<T> : IEqualityComparer<T> 8 { 9 public CustomEqualityComparer(Func<T, T, bool> equals, Func<T, int> getHashCode = null) 10 { 11 this.equals = equals; 12 this.getHashCode = getHashCode; 13 } 14 private readonly Func<T, int> getHashCode; 15 private readonly Func<T, T, bool> equals; 16 17 public bool Equals(T x, T y) 18 { 19 return equals?.Invoke(x, y) ?? false; 20 } 21 22 public int GetHashCode(T obj) 23 { 24 return getHashCode?.Invoke(obj) ?? 0; 25 } 26 } 27 28 public interface IFruit 29 { 30 int Weight { get; set; } 31 int Price { get; set; } 32 } 33 34 public class Apple : IFruit 35 { 36 public int Weight { get; set; } 37 public int Price { get; set; } 38 } 39 40 public class Orange : IFruit 41 { 42 public int Weight { get; set; } 43 public int Price { get; set; } 44 } 45 46 class Program 47 { 48 static void Main(string[] args) 49 { 50 List<Apple> apples = new List<Apple>() 51 { 52 new Apple() { Weight = 10, Price = 10 }, 53 new Apple() { Weight = 20, Price = 20 }, 54 }; 55 List<Orange> oranges = new List<Orange>() 56 { 57 new Orange() { Weight = 20, Price = 20 }, 58 new Orange() { Weight = 30, Price = 30 }, 59 }; 60 var comparer = new CustomEqualityComparer<IFruit>( 61 (a, b) => a.Price == b.Price && a.Weight == b.Weight); 62 var fruits = apples.Union(oranges, comparer); 63 foreach (var fruit in fruits) 64 { 65 Console.WriteLine(fruit.Weight); 66 } 67 Console.ReadKey(); 68 } 69 } 70}
投稿2019/04/27 15:31
編集2019/04/27 15:56総合スコア28660
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/04/27 16:41
2019/04/28 04:09 編集
0
しかし、List<AppleAndOrange>のような、両方の型を入れられるようなListを作って、
AppleAndOrange クラスは(名前、重さ、値段、色、出荷日…)というような構造になるのでしょうか?
List<Apple> と List<Orange> から List<AppleAndOrange> を作るということでよければ、以下の記事の 1 または 2 いずれかの方法で Distinct メソッドで「重さ」と「値段」の重複をチェックできるようにしていかがですか?
匿名型と Distinct メソッド
http://surferonwww.info/BlogEngine/post/2015/12/08/anonymous-type-and-distinct-method.aspx
不明点がある場合、やってみたがうまくいかない場合は連絡ください。
【追記】
上に紹介した記事「匿名型と Distinct メソッド」の 1. の方法で Distinct メソッドによる重複排除ができるようにしたサンプルを書いておきます。これでは質問者さんの目的が果たせない場合は、どこをどう直すべきか具体的に連絡ください。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleAppDistinct { public class Apple { public int Weight { get; set; } public int Price { get; set; } } public class Orange { public int Weight { get; set; } public int Price { get; set; } } public class AppleAndOrange : IEquatable<AppleAndOrange> { public string Name { get; set; } public int Weight { get; set; } public int Price { get; set; } public bool Equals(AppleAndOrange other) { if (Object.ReferenceEquals(other, null)) return false; if (Object.ReferenceEquals(this, other)) return true; return Price.Equals(other.Price) && Weight.Equals(other.Weight); } // If Equals() returns true for a pair of objects // then GetHashCode() must return the same value for these objects. public override int GetHashCode() { return Price.GetHashCode() ^ Weight.GetHashCode(); } } class Program { static void Main(string[] args) { List<Apple> apples = new List<Apple> { new Apple { Price = 100, Weight = 100 }, new Apple { Price = 110, Weight = 110 }, new Apple { Price = 120, Weight = 120 }, new Apple { Price = 130, Weight = 130 }, new Apple { Price = 140, Weight = 140 } }; List<Orange> oranges = new List<Orange> { new Orange { Price = 100, Weight = 110 }, new Orange { Price = 105, Weight = 100 }, new Orange { Price = 120, Weight = 120 }, new Orange { Price = 130, Weight = 125 }, new Orange { Price = 140, Weight = 140 } }; List<AppleAndOrange> applesAndOranges = new List<AppleAndOrange>(); foreach(Apple a in apples) { applesAndOranges.Add(new AppleAndOrange { Name = "Apple", Price = a.Price, Weight = a.Weight }); } foreach (Orange o in oranges) { applesAndOranges.Add(new AppleAndOrange { Name = "Orange", Price = o.Price, Weight = o.Weight }); } foreach (AppleAndOrange x in applesAndOranges) { Console.WriteLine($"Name: {x.Name}, Price: {x.Price}, Weight: {x.Weight}"); } Console.WriteLine("-------------------------"); foreach (AppleAndOrange x in applesAndOranges.Distinct()) { Console.WriteLine($"Name: {x.Name}, Price: {x.Price}, Weight: {x.Weight}"); } } } }
実行結果は以下の通りとなります。
Name: Apple, Price: 100, Weight: 100
Name: Apple, Price: 110, Weight: 110
Name: Apple, Price: 120, Weight: 120
Name: Apple, Price: 130, Weight: 130
Name: Apple, Price: 140, Weight: 140
Name: Orange, Price: 100, Weight: 110
Name: Orange, Price: 105, Weight: 100
Name: Orange, Price: 120, Weight: 120
Name: Orange, Price: 130, Weight: 125
Name: Orange, Price: 140, Weight: 140
------------------
Name: Apple, Price: 100, Weight: 100
Name: Apple, Price: 110, Weight: 110
Name: Apple, Price: 120, Weight: 120
Name: Apple, Price: 130, Weight: 130
Name: Apple, Price: 140, Weight: 140
Name: Orange, Price: 100, Weight: 110
Name: Orange, Price: 105, Weight: 100
Name: Orange, Price: 130, Weight: 125
投稿2019/04/27 02:27
編集2019/04/27 03:46退会済みユーザー
総合スコア0
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。