0

LINQ を使用して、GroupJoin を複数の不明なキーで動作させようとしています。

匿名型のソリューションを見てきましたが、キーは常に事前定義されていました。私の場合、それらはユーザー定義であるため、コンパイル時にその情報を知ることはできません。キー値のリストとキー値の配列を使用しようとしましたが、一致しません。

だから...これは魅力のように機能します:

Func<Component, string> getKeyValue = x => x.Attributes                            //from attributes
                                            .Single(a => a.Name == _keyAttribute) //selects the key attribute
                                            .Value;                              //gets attribute value

var leftJoin = source.GroupJoin(target,                  //join
                                getKeyValue,            //on the same
                                getKeyValue,           //condition
                                (src, corresp) => new
                                {
                                   src,
                                   corresp
                                })
                    .SelectMany(z => z.corresp.DefaultIfEmpty()
                                              .Select(tgt => new { z.src, tgt })) //selects matching
                    .ToList();                                                   //source and target

しかし、これはしません:

Func<Component, List<string>> getKeyValues = x => x.Attributes                 //from attributes
                                 .Where(a => _keyAttributes.Contains(a.Name)) //selects key attributes
                                 .OrderBy(a => a.Name)                       //order them by name
                                 .Select(a => a.Value)                      //gets attributes' values
                                 .ToList();
var leftJoin = source.GroupJoin(target,                  //join
                                getKeyValues,           //on the same
                                getKeyValues,          //condition
                                (src, corresp) => new
                                {
                                   src,
                                   corresp
                                })
                    .SelectMany(z => z.corresp.DefaultIfEmpty()
                                              .Select(tgt => new { z.src, tgt })) //selects matching
                    .ToList();                                                   //source and target

それが役立つ場合、これは私が取り組んでいる構造です:

List<string> _keyAttributes;
List<Component> source;
List<Component> target;

[DataContract]
public class Component
{
   [DataMember]
   public List<Attribute> Attributes { get; set; }

   public Component()
   {
      new List<Attribute>();
   }
}

[DataContract]
public class Attribute
{
    [DataMember]
    public string Name { get; set;}
    [DataMember]
    public string Value { get; set;}
}   

LINQ ライブラリを使用してこれを解決する方法はありますか?それには独自の GroupJoin 拡張メソッドが必要ですか?

4

1 に答える 1

0

問題は、提供する getKeyValues セレクターが比較のためにListそれぞれから a を返すことです。Componentそれぞれから返されたものは参照Listによって比較されるため、基本的には次のようになります。

var listA = new List<string> { "SomeString" };
var listB = new List<string> { "SomeString" };

bool areListsEqual = listA == listB;

areListsEqual参照によって比較されるため、false を返します。基本的に必要なのは、異なるものEqualityComparer(のオーバーロードを介して追加できる) か、 valueGroupJoinでプロパティを比較する方法が必要です。

動作するものの例 (ただし、必ずしも良い方法であるとは限りません) は次のとおりです。

Func<Component, string> getKeyValues = x =>
    string.Join(",", x.Attributes
                      .Where(a => _keyAttributes.Contains(a.Name))
                      .OrderBy(a => a.Name)
                      .Select(a => a.Value).ToArray());

これにより、各リストの値を表す文字列が作成され、比較に使用されます。より良い方法はEqualityComparer、含まれる値に基づいてリストを実際に等しくする独自のロジックを持つ を使用することです。2 つのリストを比較する方法については、こちらを参照してください。

于 2013-07-12T17:09:06.773 に答える