2

私は2つのリストを一緒に「結合」しようとしています。両方のリストは同じタイプであり、そのタイプの各インスタンスには一意のキーがあります。両方のリストに同じキーを持つインスタンスがある場合は、カスタムマージ関数を使用して2つのインスタンスをマージしたいと思います。アイテムの最終リストには、マージされた要素に加えて、最初に2つのリストのいずれかにのみ含まれていたインスタンスが含まれている必要があります。

これはUnionJoinに似ていますが、それぞれに微妙に異なるようです。ユニオンは正しいキーのリストを提供しますが、同じキーを共有するインスタンスをマージする機能はありません。インスタンスの1つを返し、他のインスタンスを無視するだけです。結合を使用すると、関数を指定して繰り返しインスタンスをマージできますが、どちらか一方ではなく、両方のリストにある要素のみが返されます。

これを行うための優れた組み込みの方法を見逃したことがありますか?

4

2 に答える 2

4

これは非常に簡単です。

次のような機能があると仮定できる場合merge

Func<T, T, T> merge = (a, b) => /* your result here */;

次に、これは機能するはずです:

var intersects = listA.Join(listB, x => x.Id, x => x.Id, (a, b) => merge(a, b));
var excepts = listA.Except(listB).Concat(listB.Except(listA));

var results = intersects.Concat(excepts);

これがうまくいくかどうか教えてください。

于 2012-08-27T02:12:01.817 に答える
2

リストに重複IDがないと仮定すると、必要なのは外部結合です。これが実装です...私は最適なパフォーマンスを保証しません:

public static class LinqEx
{
    public static IEnumerable<TResult> 
        LeftOuterJoin<TOuter, TInner, TKey, TResult>(
            this IEnumerable<TOuter> outer, 
            IEnumerable<TInner> inner, 
            Func<TOuter, TKey> outerKeySelector, 
            Func<TInner, TKey> innerKeySelector, 
            Func<TOuter, TInner, TResult> resultSelector)
    {
        return outer
            .GroupJoin(
                inner, 
                outerKeySelector, 
                innerKeySelector, 
                (a, b) => new
                {
                    a,
                    b
                })
            .SelectMany(
                x => x.b.DefaultIfEmpty(), 
                (x, b) => resultSelector(x.a, b));
    }

    public static IEnumerable<TResult> 
        FullOuterJoin<TSet1, TSet2, TKey, TResult>(
            this IEnumerable<TSet1> set1, 
            IEnumerable<TSet2> set2, 
            Func<TSet1, TKey> set1Selector, 
            Func<TSet2, TKey> set2Selector, 
            Func<TSet1, TSet2, TResult> resultSelector)
    {
        var leftJoin = set1.
            LeftOuterJoin(
                set2, 
                set1Selector, 
                set2Selector, 
                (s1, s2) => new {s1, s2});
        var rightJoin = set2
            .LeftOuterJoin(
                set1, 
                set2Selector, 
                set1Selector, 
                (s2, s1) => new {s1, s2});
        return leftJoin.Union(rightJoin)
            .Select(x => resultSelector(x.s1, x.s2));

    }
}

それで:

list1.FullOuterJoin(
    list2, 
    list1Item => list1Item.Id,
    list2Item => list2Item.Id,
    (list1Item, list2Item) => {
      if(listItem1!=null && listItem2!=null)
      {
        return merge(listItem1, listItem2);
      }
      return listItem1 ?? listItem2;
    })
于 2012-08-27T02:00:58.080 に答える