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

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

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

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

LINQ

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

Q&A

解決済

3回答

12533閲覧

2つの異なる型のリストを比較し、データ抽出

teraotailnosuke

総合スコア52

C#

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

LINQ

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

0グッド

1クリップ

投稿2016/11/25 23:41

C#で以下のような2つの型のリストを比較し、片方にしかないものを抽出する方法を教えてください。
(同じ型同士ならExcept拡張メソッドで一発なのかと思いますが)

知りたいのは

  • 簡潔で読みやすい、分かりやすさ優先パターン
  • 処理速度優先パターン

の2つの方針での実現方法。
2つを同時に満たせればそれが一番理想です。

C#のバージョンは6.0です。
実現方法は標準提供されている機能を使う限り、何でもありです。

CSharp

1public class ClassA 2{ 3 public Guid Key { get; set; } 4 public string Name { get; set; } 5} 6 7public class ClassB 8{ 9 private int field1; 10 private double field2; 11 public Guid Key { get; set; } 12} 13 14public void FunctionX(List<ClassA>listA, List<ClassB>listB) 15{ 16 // TODO: listAとlistBのKeyを比較し、listAにしか無いKeyのNameをコンソールに出力 17}

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

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

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

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

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

guest

回答3

0

ClassA と ClassB が持つ Key プロパティが同じ意味合いなら
まとめて ISample などのインターフェースにしてはどうでしょうか。
そして IEqualityComparer<T> を利用します。
こうすることで Except<T> 拡張メソッドが使えるようになります。

C#

1namespace ConsoleApplication1 2{ 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 var rand = new Random(); 12 var listA = Enumerable.Range(0, 10).Select((x, i) => new ClassA() { Key = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)i), Name = i + "太郎" }).ToList(); 13 var listB = new List<ClassB>() 14 { 15 new ClassB() { Key = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)0) }, 16 new ClassB() { Key = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)3) }, 17 new ClassB() { Key = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)5) }, 18 new ClassB() { Key = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)8) }, 19 }; 20 FunctionX(listA, listB); 21 22 Console.ReadKey(); 23 } 24 25 public static void FunctionX(List<ClassA> listA, List<ClassB> listB) 26 { 27 foreach (var c in listA.Except<ISample>(listB, ClassComarer.CompareAB)) 28 { 29 var a = c as ClassA; 30 Console.WriteLine(a.Name); 31 } 32 } 33 } 34 35 public interface ISample 36 { 37 Guid Key { get; } 38 } 39 40 public class ClassA : ISample 41 { 42 public Guid Key { get; set; } 43 public string Name { get; set; } 44 } 45 46 public class ClassB : ISample 47 { 48 private int field1; 49 private double field2; 50 public Guid Key { get; set; } 51 } 52 53 public class ClassComarer : IEqualityComparer<ISample> 54 { 55 public static readonly ClassComarer CompareAB = new ClassComarer(); 56 57 public bool Equals(ISample x, ISample y) 58 { 59 return x.Key == y.Key; 60 } 61 62 public int GetHashCode(ISample obj) 63 { 64 return obj == null ? 0 : 1; 65 } 66 } 67}

投稿2016/11/26 01:42

twyujiro15

総合スコア217

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

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

guest

0

最初に思いついた方法を書きます。

C#

1//サンプルコード 2 public void FunctionX(List<ClassA> listA, List<ClassB> listB) 3 { 4 var keys = listB.Select(b => b.Key).ToArray(); 5 foreach (var item in listA.Where(list => !keys.Contains(list.Key))) 6 { 7 Console.WriteLine(item.Name); 8 } 9 }

実際にはメソッドのパラメータを検討した方が良さそうな気もしますがそれは今回直接関係ないため省略。

投稿2016/11/26 03:06

編集2016/11/26 07:39
nakit

総合スコア410

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

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

teraotailnosuke

2016/11/26 07:32

これだと両方のリストにあるものを抽出になってしまいませんか?
nakit

2016/11/26 07:39

勘違いしていました。確かにこれだとlistBに存在するキーを抽出してしまいます。 Where拡張メソッドの条件を修正しました。
guest

0

ベストアンサー

自分は大量の要素があるならDictionaryやHashSetを使うことを最初に考えます。LINQを使う時ToDictionaryが便利ではありますが、本件なら抽出したいのはAの要素だけでありDictionaryは冗長な気がするのでHashSetを使い下記のPattern-Aのようにすると思います。

ただし、Bの要素数が十分小さくAの要素もそれほど大きくなく、何度も行わないような処理ならば下記のPattern-Bで済ませてしまうかも知れません。

C#

1//Pattern-A: Bの要素数がそれなりにある場合 2public void FunctionX(List<ClassA>listA, List<ClassB>listB) 3{ 4 HashSet<Guid> set = new HashSet<Guid>(listB.Select(e => e.Key)); 5 for (var element in listA.Where(e => !set.Contains(e.Key))) { 6 Console.WriteLine(element.Name); 7 } 8} 9 10//Pattern-B: Bの要素数が少なくAの要素数もそれほどない場合 11// (要素数が少ないという条件があるのでメソッド(関数)として作らないかもしれない) 12foreach (var element in listA.Where(a => !listB.Any(b => a.Key == b.Key))) { 13 Console.WriteLine(element.Name); 14}

投稿2016/11/26 09:04

編集2016/11/26 15:58
KSwordOfHaste

総合スコア18394

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

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

nakit

2016/11/26 09:21

確かに処理速度的にもHashSetを利用するのが良さそうです。 ※本文内、誤字でHasetSetになっています。
KSwordOfHaste

2016/11/26 14:11

誤字の指摘ありがとうございます。訂正しておきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問