QA@IT

VB.NET LINQ 複数条件でのJOINの方法

9870 PV

LINQ to Objectでクラスのコレクション同士を複数条件でJoinしたいのですが、どうしたらいいのか悩んでいます。

あるコード同士でJOINしたい。でも、コードが入ってないものも含めたい場合
(以下の例ではCode1が一致する、または入ってないもの)

 Dim Query = From RecA In ListA
             Join RecB In ListB
             On RecA.Code1 Equals RecB.Code1
                Or RecA.Code1=""  ←こういう書き方はできない

簡単そうで、いろいろ試したつもりですが解決できません。
良い方法があればアドバイスの程よろしくお願い致します。

回答

やりたいことが良く理解できてないのですが、以下の記事のようなことは目的に合わないでしょうか?

方法 : 左外部結合を実行する (C# プログラミング ガイド)
https://msdn.microsoft.com/ja-jp/library/bb397895.aspx

ハズレだったらすみません。その場合、ListA と ListB の構造をもっと詳しく書いていただけませんか?

【2015/12/2 14:50 追記】

上に紹介した記事の左外部結合の延長線上で、それに where 句で「Code1が一致する、または入ってないもの」条件を追加してはいかがですか?

もっとスマートな方法はあるかもしれませんし質問者さんの目的に 100% 沿っているかどうか分かりませんが、以下のコード例で取得できることは確認しました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleAppLinq
{
    class Program
    {
        static void Main(string[] args)
        {
            List<A> listA = new List<A> {
                new A { Code = "1", Name = "Hedlund" },
                new A { Code = "2", Name = "Adams" },
                new A { Code = "3", Name = "Weiss" },
                new A { Code = "4", Name = "Huff" },
                new A { Code = "5", Name = "佐藤" },
                new A { Code = "", Name = "田中" }};

            List<B> listB = new List<B> {
                new B { Code = "1", Name = "Barley" },
                new B { Code = "2", Name = "Boots" },
                new B { Code = "3", Name = "Whiskers" },
                new B { Code = "4", Name = "Blue Moon" }};

            var list = from a in listA
                       join b in listB
                       on a.Code equals b.Code into g
                       from s in g.DefaultIfEmpty()
                       where a.Code == String.Empty || s != null
                       select new { a.Code, a.Name, bName = (s == null? String.Empty : s.Name) };

            foreach (var l in list)
            {
                Console.WriteLine(l.Code + ", " + l.Name + ", " + l.bName);
            }

            // 実行結果は:

            // 1, Hedlund, Barley
            // 2, Adams, Boots
            // 3, Weiss, Whiskers
            // 4, Huff, Blue Moon
            // , 田中,

        }

    }

    public class A
    {
        public string Code { get; set; }
        public string Name { get; set; }
    }

    public class B
    {
        public string Code { get; set; }
        public string Name { get; set; }
    }
}
編集 履歴 (1)
  • 左外部結合は、結合先に一致する物が無くても抽出対象になりますが、今欲しいのは「1.コードが一致するもの+2.コードが空のもの」になります。

    構造と言ってもコードだけ意識してましてこのような感じです。
    Class ListA
     Public Code1 As String
     Public Name As String
    End Class
    (ListBも同様)
    -
  • ListA は上記で間違いないのですか? それで間違いないとすると From RecA In ListA の方はいかが? -
  • ご回答ありがとうございます。
    大変失礼しました。
    お伝えしたかったのは以下の内容です。
    Dim ListA As New List(Of ClassA)
    Class ClassA
     Public Code1 As String
     Public Name As String
    End Class
    -
  • であれば、紹介した記事の応用でできると思います(もっとスマートな方法があるかもしれませんが)。一応検証してから上の回答欄に追記します。 -
  • 素晴らしいです!!
    VBに書き換えるのに少し考えましたが、こちらでも同じように目的の結果が得られました。
    もっと考えなければいけませんね。
    ありがとうございました!!
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。