লিনকিউ - সম্পূর্ণ আউটআর জয়েন করুন


202

আমার কাছে লোকের আইডি এবং তাদের প্রথম নাম এবং তাদের আইডি এবং তাদের নামের একটি তালিকা রয়েছে। কিছু লোকের প্রথম নাম নেই এবং কারওর একটি নামও নেই; আমি দুটি তালিকায় একটি সম্পূর্ণ বাইরের যোগদান করতে চাই।

সুতরাং নিম্নলিখিত তালিকা:

ID  FirstName
--  ---------
 1  John
 2  Sue

ID  LastName
--  --------
 1  Doe
 3  Smith

উত্পাদন করা উচিত:

ID  FirstName  LastName
--  ---------  --------
 1  John       Doe
 2  Sue
 3             Smith

আমি লিনকুতে নতুন (তাই আমি যখন খোঁড়া হয়ে থাকি তবে আমাকে ক্ষমা করুন) এবং 'লিনকউ আউটার জয়েনস' এর জন্য বেশ কয়েকটি সমাধান খুঁজে পেয়েছি যা সবগুলি দেখতে বেশ একই রকম, তবে বাস্তবে মনে হয় বাইরের সাথে যোগ দেয়।

আমার প্রচেষ্টা এখনও পর্যন্ত এরকম কিছু করে চলেছে:

private void OuterJoinTest()
{
    List<FirstName> firstNames = new List<FirstName>();
    firstNames.Add(new FirstName { ID = 1, Name = "John" });
    firstNames.Add(new FirstName { ID = 2, Name = "Sue" });

    List<LastName> lastNames = new List<LastName>();
    lastNames.Add(new LastName { ID = 1, Name = "Doe" });
    lastNames.Add(new LastName { ID = 3, Name = "Smith" });

    var outerJoin = from first in firstNames
        join last in lastNames
        on first.ID equals last.ID
        into temp
        from last in temp.DefaultIfEmpty()
        select new
        {
            id = first != null ? first.ID : last.ID,
            firstname = first != null ? first.Name : string.Empty,
            surname = last != null ? last.Name : string.Empty
        };
    }
}

public class FirstName
{
    public int ID;

    public string Name;
}

public class LastName
{
    public int ID;

    public string Name;
}

তবে এটি ফিরে আসে:

ID  FirstName  LastName
--  ---------  --------
 1  John       Doe
 2  Sue

আমি কি ভুল করছি?


2
আপনার কেবলমাত্র ইন-মেমরি তালিকার জন্য বা লিনক 2 এসকিএল-এর জন্য কাজ করার দরকার আছে?
জেমসফ্যাক্স

.GroupJoin () ব্যবহার করে দেখুন stackoverflow.com/questions/15595289/...
jdev.ninja

উত্তর:


122

আমি জানি না যে এটি সমস্ত ক্ষেত্রে কভার করে কিনা, যৌক্তিকভাবে এটি সঠিক বলে মনে হয়। বাম বাহ্যিক যোগদান এবং ডান বাহিরের জয়েন গ্রহণের পরে ফলাফলের ইউনিয়নটি গ্রহণ করা ধারণা।

var firstNames = new[]
{
    new { ID = 1, Name = "John" },
    new { ID = 2, Name = "Sue" },
};
var lastNames = new[]
{
    new { ID = 1, Name = "Doe" },
    new { ID = 3, Name = "Smith" },
};
var leftOuterJoin =
    from first in firstNames
    join last in lastNames on first.ID equals last.ID into temp
    from last in temp.DefaultIfEmpty()
    select new
    {
        first.ID,
        FirstName = first.Name,
        LastName = last?.Name,
    };
var rightOuterJoin =
    from last in lastNames
    join first in firstNames on last.ID equals first.ID into temp
    from first in temp.DefaultIfEmpty()
    select new
    {
        last.ID,
        FirstName = first?.Name,
        LastName = last.Name,
    };
var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin);

এটি লিখিত হিসাবে কাজ করে যেহেতু এটি লাইনকিউ অবজেক্টে রয়েছে। যদি লিনকিউ থেকে এসকিউএল বা অন্য, ক্যোয়ারী প্রসেসর নিরাপদ নেভিগেশন বা অন্যান্য ক্রিয়াকলাপ সমর্থন করে না। শর্তসাপেক্ষে মানগুলি পেতে আপনাকে শর্তসাপেক্ষ অপারেটরটি ব্যবহার করতে হবে।

অর্থাত,

var leftOuterJoin =
    from first in firstNames
    join last in lastNames on first.ID equals last.ID into temp
    from last in temp.DefaultIfEmpty()
    select new
    {
        first.ID,
        FirstName = first.Name,
        LastName = last != null ? last.Name : default,
    };

2
ইউনিয়ন সদৃশগুলি মুছে ফেলবে। আপনি যদি সদৃশ প্রত্যাশা না করে থাকেন বা প্রথমটিতে অন্তর্ভুক্ত থাকা কোনও কিছু বাদ দিতে দ্বিতীয় কোয়েরি লিখতে পারেন তবে পরিবর্তে কনক্যাট ব্যবহার করুন। এটি ইউনিয়ন এবং ইউনিয়ন
সমস্তের

3
@ ক্যাডারে ১১০ টি সদৃশ ঘটবে যদি কোনও ব্যক্তির প্রথম নাম এবং শেষ নাম থাকে, সুতরাং ইউনিয়নটি বৈধ পছন্দ।
সস

1
@ সাউস তবে একটি আইডি কলাম রয়েছে, সুতরাং ডুপ্লিকেট প্রথম এবং শেষ নাম থাকলেও আইডিটি আলাদা হওয়া উচিত
ক্যাডারেল ০

1
আপনার সমাধান আদিম ধরণের জন্য কাজ করে, তবে বস্তুর পক্ষে কাজ করে বলে মনে হয় না। আমার ক্ষেত্রে, ফার্স্টনাম একটি ডোমেন অবজেক্ট, যখন লাস্টনাম অন্য ডোমেন অবজেক্ট। আমি যখন দুটি ফলাফলকে একত্রিত করি, লিনকিউ একটি নোটসপোর্টড এক্সসেপশন নিক্ষেপ করল (ইউনিয়ন বা কনক্যাট-এ টাইপগুলি অসম্পূর্ণভাবে নির্মিত হয়)। আপনি কি অনুরূপ সমস্যা অনুভব করেছেন?
ক্যান্ডি চিউ

1
@ ক্যান্ডিচিউ: আমি আসলে কখনও এ জাতীয় মামলায় যাইনি। আমার ধারণা এটি আপনার ক্যোয়ার সরবরাহকারীর সাথে সীমাবদ্ধতা। আপনি সম্ভবত AsEnumerable()ইউনিয়ন / উপসংহার সম্পাদনের আগে কল করে সেই ক্ষেত্রে অবজেক্টগুলিতে LINQ ব্যবহার করতে চান । এটি চেষ্টা করুন এবং দেখুন যে কিভাবে। আপনি যে পথে যেতে চান তা যদি এটি না হয় তবে আমি নিশ্চিত নই যে আমি এর চেয়ে আরও বেশি সাহায্য করতে পারি।
জেফ মার্কাডো

196

আপডেট 1: সত্যিকারের জেনারেলাইজড এক্সটেনশন পদ্ধতি সরবরাহ করা FullOuterJoin
আপডেট 2: IEqualityComparertype
চ্ছিকভাবে মূল প্রকারের জন্য একটি কাস্টম গ্রহণ করা আপডেট 3 : এই বাস্তবায়নটি সম্প্রতি অংশটির হয়ে উঠেছেMoreLinq - ধন্যবাদ ছেলেরা!

সম্পাদনা যুক্ত FullOuterGroupJoin( আদর্শ )। আমি GetOuter<>প্রয়োগটিকে পুনরায় ব্যবহার করেছি, এটি ভগ্নাংশটি যতটা পারফরম্যান্স হতে পারে তার চেয়ে কম পারফরম্যান্ট করে তুলছি, তবে আমি 'হাইলেভেল' কোডের জন্য লক্ষ্য রাখছি, এখনই রক্তক্ষরণ-প্রান্তটি অনুকূল নয়,।

এটি http://ideone.com/O36nWc এ লাইভ দেখুন

static void Main(string[] args)
{
    var ax = new[] { 
        new { id = 1, name = "John" },
        new { id = 2, name = "Sue" } };
    var bx = new[] { 
        new { id = 1, surname = "Doe" },
        new { id = 3, surname = "Smith" } };

    ax.FullOuterJoin(bx, a => a.id, b => b.id, (a, b, id) => new {a, b})
        .ToList().ForEach(Console.WriteLine);
}

আউটপুট মুদ্রণ:

{ a = { id = 1, name = John }, b = { id = 1, surname = Doe } }
{ a = { id = 2, name = Sue }, b =  }
{ a = , b = { id = 3, surname = Smith } }

আপনি ডিফল্ট সরবরাহ করতেও পারেন: http://ideone.com/kG4kqO

    ax.FullOuterJoin(
            bx, a => a.id, b => b.id, 
            (a, b, id) => new { a.name, b.surname },
            new { id = -1, name    = "(no firstname)" },
            new { id = -2, surname = "(no surname)" }
        )

মুদ্রণ:

{ name = John, surname = Doe }
{ name = Sue, surname = (no surname) }
{ name = (no firstname), surname = Smith }

ব্যবহৃত পদগুলির ব্যাখ্যা:

যোগ দেওয়ার একটি শব্দ যা সম্পর্কিত সম্পর্কিত ডাটাবেস ডিজাইন থেকে নেওয়া হয়েছে:

  • একটি যোগদানের সাথে সংশ্লিষ্ট কীগুলির সাথেa উপাদান থাকা যতবার উপাদান থেকে পুনরাবৃত্তি হবে (যেমন: খালি থাকলে কিছুই ছিল না )। ডেটাবেস লিঙ্গো এটিকে কল করেb binner (equi)join
  • একটি বাহ্যিক যোগদানের সাথে উপাদানগুলি অন্তর্ভুক্ত থাকে aযার জন্য কোনও সম্পর্কিত উপাদান উপস্থিত নেই b। (যেমন: এমনকি bশূন্য থাকলেও ফলাফল )। এটি সাধারণত হিসাবে উল্লেখ করা হয়left join
  • একটি পূর্ণ বাইরের যোগদানের থেকে রেকর্ড রয়েছে a এবং সেইসাথেb যদি কোন সংশ্লিষ্ট উপাদান অন্যান্য বিদ্যমান। (যেমন aখালি থাকলেও ফলাফল )

কিছু সাধারণত নাআরডিবিএমএসে দেখা যায় হ'ল একটি গ্রুপে যোগদান [1] :

  • একটি গোষ্ঠী যোগদান করে , উপরে বর্ণিত হিসাবে একই কাজ করে, তবেa একাধিক সম্পর্কিতের জন্য উপাদানগুলি পুনরাবৃত্তি করার পরিবর্তেb , এটা গ্রুপ সংশ্লিষ্ট কী এর মাধ্যমে রেকর্ড। আপনি যখন একটি সাধারণ কী এর উপর ভিত্তি করে 'যোগদান' রেকর্ডগুলির মাধ্যমে গণনা করতে চান তখন এটি প্রায়শই সুবিধাজনক।

আরো দেখুন গ্রুপজয়াইন যা কিছু সাধারণ ব্যাকগ্রাউন্ডের ব্যাখ্যা রয়েছে।


[1] (আমি বিশ্বাস করি যে এরাকল এবং এমএসএসকিউএর মালিকানা বাড়ানো আছে)

সম্পূর্ণ কোড

এর জন্য একটি সাধারণকরণ 'ড্রপ-ইন' এক্সটেনশন ক্লাস

internal static class MyExtensions
{
    internal static IEnumerable<TResult> FullOuterGroupJoin<TA, TB, TKey, TResult>(
        this IEnumerable<TA> a,
        IEnumerable<TB> b,
        Func<TA, TKey> selectKeyA, 
        Func<TB, TKey> selectKeyB,
        Func<IEnumerable<TA>, IEnumerable<TB>, TKey, TResult> projection,
        IEqualityComparer<TKey> cmp = null)
    {
        cmp = cmp?? EqualityComparer<TKey>.Default;
        var alookup = a.ToLookup(selectKeyA, cmp);
        var blookup = b.ToLookup(selectKeyB, cmp);

        var keys = new HashSet<TKey>(alookup.Select(p => p.Key), cmp);
        keys.UnionWith(blookup.Select(p => p.Key));

        var join = from key in keys
                   let xa = alookup[key]
                   let xb = blookup[key]
                   select projection(xa, xb, key);

        return join;
    }

    internal static IEnumerable<TResult> FullOuterJoin<TA, TB, TKey, TResult>(
        this IEnumerable<TA> a,
        IEnumerable<TB> b,
        Func<TA, TKey> selectKeyA, 
        Func<TB, TKey> selectKeyB,
        Func<TA, TB, TKey, TResult> projection,
        TA defaultA = default(TA), 
        TB defaultB = default(TB),
        IEqualityComparer<TKey> cmp = null)
    {
        cmp = cmp?? EqualityComparer<TKey>.Default;
        var alookup = a.ToLookup(selectKeyA, cmp);
        var blookup = b.ToLookup(selectKeyB, cmp);

        var keys = new HashSet<TKey>(alookup.Select(p => p.Key), cmp);
        keys.UnionWith(blookup.Select(p => p.Key));

        var join = from key in keys
                   from xa in alookup[key].DefaultIfEmpty(defaultA)
                   from xb in blookup[key].DefaultIfEmpty(defaultB)
                   select projection(xa, xb, key);

        return join;
    }
}

ব্যবহারের দেখানোর জন্য সম্পাদিত FullOuterJoinএক্সটেনশন পদ্ধতি উপলব্ধ
sehe

সম্পাদিত: FullOuterGroupJoin এক্সটেনশন পদ্ধতি যোগ
sehe

4
অভিধান ব্যবহার করার পরিবর্তে, আপনি একটি লুকআপ ব্যবহার করতে পারেন , এতে আপনার সহায়ক সম্প্রসারণ পদ্ধতিতে প্রকাশিত কার্যকারিতা রয়েছে contains উদাহরণস্বরূপ, আপনি a.GroupBy(selectKeyA).ToDictionary();হিসাবে a.ToLookup(selectKeyA)এবং adict.OuterGet(key)হিসাবে লিখতে পারেন alookup[key]। কী সংগ্রহ পথ একটু, trickier, যদিও হল: alookup.Select(x => x.Keys)
ঝুঁকিপূর্ণ মার্টিন

1
@ রিস্কিমার্টিন ধন্যবাদ! এটি প্রকৃতপক্ষে পুরো জিনিসটিকে আরও মার্জিত করে তোলে। আমি উত্তর এবং আদর্শ-গুলি আপডেট করেছি । (আমি মনে করি যে কম বস্তুগুলি তাত্ক্ষণিকভাবে কার্যকর হওয়ায় পারফরম্যান্স বাড়ানো উচিত)।
sehe

1
@ রিভিয়ার যে আপনি কীগুলি অনন্য তা জানেন তবেই কাজ করে। এবং এটি / গ্রুপিং / এর পক্ষে সাধারণ ঘটনা নয়। তা বাদে হ্যাঁ, সমস্ত উপায়ে। যদি আপনি জানেন যে হ্যাশ পারফ টানতে যাচ্ছে না (নোড-ভিত্তিক পাত্রে নীতিগতভাবে আরও বেশি ব্যয় হয়, এবং হ্যাশিং বিনামূল্যে নয় এবং দক্ষতা হ্যাশ ফাংশন / বালতি স্প্রেডের উপর নির্ভর করে), এটি অবশ্যই আরও আলগোরিদিম কার্যকর হবে। সুতরাং, ছোট লোড আমি আশা করতে চাই এটা দ্রুততর নাও হতে পারে
sehe

27

আমি মনে করি গ্রহণযোগ্য উত্তর সহ এগুলির মধ্যে বেশিরভাগেরই সমস্যা রয়েছে কারণ তারা লিনকের সাথে আইকুয়ারেবলের ওপরে ভালভাবে কাজ করে না হয় হয় প্রচুর সার্ভারের রাউন্ড ট্রিপ করে এবং খুব বেশি ডেটা রিটার্ন করে, বা খুব বেশি ক্লায়েন্টের মৃত্যুদন্ড কার্যকর করে।

আইনিম্যারেবলের জন্য আমি শেহের উত্তর বা অনুরূপ পছন্দ করি না কারণ এর অত্যধিক মেমরির ব্যবহার রয়েছে (একটি সহজ 10000000 দুটি তালিকার লিঙ্কপ্যাড আমার 32 জিবি মেশিনে মেমরি থেকে বেরিয়েছে)।

এছাড়াও, অন্যদের বেশিরভাগই যথাযথ ফুল আউটার জয়েন বাস্তবায়িত করে না কারণ তারা ডান অ্যান্টি সেমি জয়েন্টের সাথে কনক্যাটের পরিবর্তে ডান জোড় যুক্ত ইউনিয়ন ব্যবহার করছে, যা ফলাফল থেকে ডুপ্লিকেট অভ্যন্তরীণ জোড় সারিগুলি সরিয়ে দেয় না, তবে বাম বা ডান ডেটাতে মূলত অস্তিত্ব রয়েছে এমন কোনও যথাযথ সদৃশ।

সুতরাং এখানে আমার এক্সটেনশানগুলি যা এই সমস্ত বিষয় পরিচালনা করে, এসকিউএল উত্পন্ন করার পাশাপাশি লিনকিউ-তে যোগদানকে সরাসরি এসকিউএল এ সরাসরি প্রয়োগ করে, সার্ভারে এক্সিকিউটিভ করে, এবং দ্রুত এবং স্মরণে অন্যের তুলনায় কম থাকে:

public static class Ext {
    public static IEnumerable<TResult> LeftOuterJoin<TLeft, TRight, TKey, TResult>(
        this IEnumerable<TLeft> leftItems,
        IEnumerable<TRight> rightItems,
        Func<TLeft, TKey> leftKeySelector,
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TResult> resultSelector) {

        return from left in leftItems
               join right in rightItems on leftKeySelector(left) equals rightKeySelector(right) into temp
               from right in temp.DefaultIfEmpty()
               select resultSelector(left, right);
    }

    public static IEnumerable<TResult> RightOuterJoin<TLeft, TRight, TKey, TResult>(
        this IEnumerable<TLeft> leftItems,
        IEnumerable<TRight> rightItems,
        Func<TLeft, TKey> leftKeySelector,
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TResult> resultSelector) {

        return from right in rightItems
               join left in leftItems on rightKeySelector(right) equals leftKeySelector(left) into temp
               from left in temp.DefaultIfEmpty()
               select resultSelector(left, right);
    }

    public static IEnumerable<TResult> FullOuterJoinDistinct<TLeft, TRight, TKey, TResult>(
        this IEnumerable<TLeft> leftItems,
        IEnumerable<TRight> rightItems,
        Func<TLeft, TKey> leftKeySelector,
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TResult> resultSelector) {

        return leftItems.LeftOuterJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector).Union(leftItems.RightOuterJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector));
    }

    public static IEnumerable<TResult> RightAntiSemiJoin<TLeft, TRight, TKey, TResult>(
        this IEnumerable<TLeft> leftItems,
        IEnumerable<TRight> rightItems,
        Func<TLeft, TKey> leftKeySelector,
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TResult> resultSelector) {

        var hashLK = new HashSet<TKey>(from l in leftItems select leftKeySelector(l));
        return rightItems.Where(r => !hashLK.Contains(rightKeySelector(r))).Select(r => resultSelector(default(TLeft),r));
    }

    public static IEnumerable<TResult> FullOuterJoin<TLeft, TRight, TKey, TResult>(
        this IEnumerable<TLeft> leftItems,
        IEnumerable<TRight> rightItems,
        Func<TLeft, TKey> leftKeySelector,
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TResult> resultSelector)  where TLeft : class {

        return leftItems.LeftOuterJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector).Concat(leftItems.RightAntiSemiJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector));
    }

    private static Expression<Func<TP, TC, TResult>> CastSMBody<TP, TC, TResult>(LambdaExpression ex, TP unusedP, TC unusedC, TResult unusedRes) => (Expression<Func<TP, TC, TResult>>)ex;

    public static IQueryable<TResult> LeftOuterJoin<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector) {

        var sampleAnonLR = new { left = default(TLeft), rightg = default(IEnumerable<TRight>) };
        var parmP = Expression.Parameter(sampleAnonLR.GetType(), "p");
        var parmC = Expression.Parameter(typeof(TRight), "c");
        var argLeft = Expression.PropertyOrField(parmP, "left");
        var newleftrs = CastSMBody(Expression.Lambda(Expression.Invoke(resultSelector, argLeft, parmC), parmP, parmC), sampleAnonLR, default(TRight), default(TResult));

        return leftItems.AsQueryable().GroupJoin(rightItems, leftKeySelector, rightKeySelector, (left, rightg) => new { left, rightg }).SelectMany(r => r.rightg.DefaultIfEmpty(), newleftrs);
    }

    public static IQueryable<TResult> RightOuterJoin<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector) {

        var sampleAnonLR = new { leftg = default(IEnumerable<TLeft>), right = default(TRight) };
        var parmP = Expression.Parameter(sampleAnonLR.GetType(), "p");
        var parmC = Expression.Parameter(typeof(TLeft), "c");
        var argRight = Expression.PropertyOrField(parmP, "right");
        var newrightrs = CastSMBody(Expression.Lambda(Expression.Invoke(resultSelector, parmC, argRight), parmP, parmC), sampleAnonLR, default(TLeft), default(TResult));

        return rightItems.GroupJoin(leftItems, rightKeySelector, leftKeySelector, (right, leftg) => new { leftg, right }).SelectMany(l => l.leftg.DefaultIfEmpty(), newrightrs);
    }

    public static IQueryable<TResult> FullOuterJoinDistinct<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector) {

        return leftItems.LeftOuterJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector).Union(leftItems.RightOuterJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector));
    }

    private static Expression<Func<TP, TResult>> CastSBody<TP, TResult>(LambdaExpression ex, TP unusedP, TResult unusedRes) => (Expression<Func<TP, TResult>>)ex;

    public static IQueryable<TResult> RightAntiSemiJoin<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector) {

        var sampleAnonLgR = new { leftg = default(IEnumerable<TLeft>), right = default(TRight) };
        var parmLgR = Expression.Parameter(sampleAnonLgR.GetType(), "lgr");
        var argLeft = Expression.Constant(default(TLeft), typeof(TLeft));
        var argRight = Expression.PropertyOrField(parmLgR, "right");
        var newrightrs = CastSBody(Expression.Lambda(Expression.Invoke(resultSelector, argLeft, argRight), parmLgR), sampleAnonLgR, default(TResult));

        return rightItems.GroupJoin(leftItems, rightKeySelector, leftKeySelector, (right, leftg) => new { leftg, right }).Where(lgr => !lgr.leftg.Any()).Select(newrightrs);
    }

    public static IQueryable<TResult> FullOuterJoin<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector) {

        return leftItems.LeftOuterJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector).Concat(leftItems.RightAntiSemiJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector));
    }
}

রাইট অ্যান্টি-সেমি-জয়েনের মধ্যে পার্থক্যটি বেশিরভাগ ক্ষেত্রে লিনাক টু অবজেক্টস বা উত্সটিতে রয়েছে, তবে চূড়ান্ত উত্তরে সার্ভারে (এসকিউএল) পার্থক্য তৈরি করে একটি অপ্রয়োজনীয় অপসারণ JOIN

লাম্বডায় একটি Expressionমার্জ করার জন্য হ্যান্ড কোডিংটি Expression<Func<>>লিনককিটের সাহায্যে উন্নত করা যেতে পারে তবে ভাষা / সংকলক যদি এর জন্য কিছু সহায়তা যুক্ত করে থাকে তবে এটি ভাল হবে। FullOuterJoinDistinctএবং RightOuterJoinফাংশন সম্পূর্ণতার জন্য অন্তর্ভুক্ত করা হয়েছে, কিন্তু আমি পুনরায় বাস্তবায়ন হয়নিFullOuterGroupJoin এখনো।

আমি সম্পূর্ণ বাইরের জোড়ার জন্য আরেকটি সংস্করণ লিখেছিIEnumerable মামুলি ক্ষেত্রে অনুশীলনযোগ্য, সেখানে কমপক্ষে ছোট সংগ্রহের ক্ষেত্রে ডান অ্যান্টি আধা সেমিনের সাথে বাম বাহ্যিক জোড় সংমিশ্রণের চেয়ে প্রায় 50% দ্রুততর ক্ষেত্রে সংযুক্তির আরও । এটি একবারে বাছাইয়ের পরে প্রতিটি সংগ্রহের মধ্য দিয়ে যায়।

আমি কাস্টম সম্প্রসারণের পরিবর্তে EF এর সাথে কাজ করে এমন একটি সংস্করণের জন্য আরও একটি উত্তর যুক্ত করেছি Invoke


কিসের সাথে চুক্তি TP unusedP, TC unusedC? তারা কি আক্ষরিক অব্যবহৃত?
রুডি

হ্যাঁ, তারা শুধু ধরনের ক্যাপচার উপস্থিত TP, TC, TResultসঠিক তৈরি করতে Expression<Func<>>। আমি আমি তাদের সাথে প্রতিস্থাপন করতে পারে অনুমিত _, __, ___পরিবর্তে, কিন্তু যে কোনো পরিষ্কার বলে মনে হচ্ছে না যে পর্যন্ত না C # এর পরিবর্তে ব্যবহার করার জন্য একটি সঠিক পরামিতি ওয়াইল্ডকার্ড হয়েছে।
নেটমেজ

1
@MarcL। আমি 'ক্লান্তিকর' সম্পর্কে তেমন নিশ্চিত নই - তবে আমি সম্মত এই উত্তরটি এই প্রসঙ্গে খুব দরকারী। চিত্তাকর্ষক স্টাফ (যদিও এটি আমার কাছে
লিনাক

3
আমি হচ্ছি The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.। এই কোড সহ কোনও বিধিনিষেধ আছে? আমি আইকুয়েবিয়েলস
লার্নার

1
আমি একটি নতুন উত্তর যুক্ত করেছি যা Invokeএকটি কাস্টমকে ExpressionVisitorইনলাইন করার জন্য প্রতিস্থাপন করে Invokeযাতে এটি EF এর সাথে কাজ করা উচিত। আপনি এটি চেষ্টা করতে পারেন?
নেটমেজ

7

এটি করার জন্য এখানে একটি এক্সটেনশন পদ্ধতি রয়েছে:

public static IEnumerable<KeyValuePair<TLeft, TRight>> FullOuterJoin<TLeft, TRight>(this IEnumerable<TLeft> leftItems, Func<TLeft, object> leftIdSelector, IEnumerable<TRight> rightItems, Func<TRight, object> rightIdSelector)
{
    var leftOuterJoin = from left in leftItems
        join right in rightItems on leftIdSelector(left) equals rightIdSelector(right) into temp
        from right in temp.DefaultIfEmpty()
        select new { left, right };

    var rightOuterJoin = from right in rightItems
        join left in leftItems on rightIdSelector(right) equals leftIdSelector(left) into temp
        from left in temp.DefaultIfEmpty()
        select new { left, right };

    var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin);

    return fullOuterJoin.Select(x => new KeyValuePair<TLeft, TRight>(x.left, x.right));
}

3
+1 টি। আর ⟗ এস = (আর ⟕ এস) ∪ (আর ⟖ এস), যার অর্থ একটি সম্পূর্ণ বাহ্যিক জোড় = বাম বাহিরের জোড় ইউনিয়ন সমস্ত ডান বাহিরের যোগ! আমি এই পদ্ধতির সরলতার প্রশংসা করি।
তমুসজেরোয়েস

1
@ তমুসজেআরয়েস Unionডুপ্লিকেটগুলি বাদ দেয়, তাই যদি মূল ডেটাতে সদৃশ সারি থাকে তবে সেগুলি ফলাফল হতে পারে না।
নেটমেজ 31'19

দুর্দান্ত পয়েন্ট! ডুপ্লিকেটগুলি অপসারণ করা থেকে রোধ করতে চাইলে একটি অনন্য আইডি যুক্ত করুন। হ্যাঁ. ইউনিয়নটি কিছুটা অপ্রয়োজনীয় যদি না আপনি ইঙ্গিত করতে না পারেন যে কোনও অনন্য আইডি রয়েছে এবং ইউনিয়নটি সমস্ত ইউনিয়নে স্যুইচ করে (অভ্যন্তরীণ হিউরিস্টিক্স / অপ্টিমাইজেশনের মাধ্যমে)। তবে এটি কাজ করবে।
তমুসজেয়ার্স


7

আমি অনুমান করছি @ শেহের দৃষ্টিভঙ্গি আরও দৃ is়, তবে যতক্ষণ না আমি এটিকে আরও ভাল করে বুঝতে পারছি, আমি নিজেকে @ মাইকেলসান্ডারের এক্সটেনশনটি থেকে লাফানো-ফ্রোগিং দেখতে পাচ্ছি। আমি এখানে বর্ণিত বিল্ট-ইন এনিউরেবল.জাইন () পদ্ধতির সিনট্যাক্স এবং রিটার্ন টাইপের সাথে মেলে এটি পরিবর্তন করেছি । @ জেফমারকাডোর সমাধানের অধীনে @ ক্যাডারেল ০ এর মন্তব্যে আমি "স্বতন্ত্র" প্রত্যয় যুক্ত করেছি।

public static class MyExtensions {

    public static IEnumerable<TResult> FullJoinDistinct<TLeft, TRight, TKey, TResult> (
        this IEnumerable<TLeft> leftItems, 
        IEnumerable<TRight> rightItems, 
        Func<TLeft, TKey> leftKeySelector, 
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TResult> resultSelector
    ) {

        var leftJoin = 
            from left in leftItems
            join right in rightItems 
              on leftKeySelector(left) equals rightKeySelector(right) into temp
            from right in temp.DefaultIfEmpty()
            select resultSelector(left, right);

        var rightJoin = 
            from right in rightItems
            join left in leftItems 
              on rightKeySelector(right) equals leftKeySelector(left) into temp
            from left in temp.DefaultIfEmpty()
            select resultSelector(left, right);

        return leftJoin.Union(rightJoin);
    }

}

উদাহরণস্বরূপ, আপনি এটি এর মতো ব্যবহার করবেন:

var test = 
    firstNames
    .FullJoinDistinct(
        lastNames,
        f=> f.ID,
        j=> j.ID,
        (f,j)=> new {
            ID = f == null ? j.ID : f.ID, 
            leftName = f == null ? null : f.Name,
            rightName = j == null ? null : j.Name
        }
    );

ভবিষ্যতে, আমি আরও শিখার পরে, আমার মনে হয় যে @ জনপ্রিয়তার জনপ্রিয়তা দেখিয়ে আমি তার যুক্তিতে চলে যাব। তবে তারপরেও আমাকে সাবধানতা অবলম্বন করতে হবে, কারণ আমি মনে করি যে কমপক্ষে একটি ওভারলোড থাকা বিদ্যমান "। জয়েন্ট ()" পদ্ধতির সাথে যদি সম্ভব হয় তবে দুটি কারণেই এটি সম্ভব হবে:

  1. পদ্ধতিগুলিতে ধারাবাহিকতা সময় বাঁচাতে, ত্রুটিগুলি এড়াতে এবং অনিচ্ছাকৃত আচরণ এড়াতে সহায়তা করে।
  2. ভবিষ্যতে যদি কোনও অফ-অফ-দ্য বাক্স থাকে ".ফুলজয়াইন ()" পদ্ধতিটি ভবিষ্যতে থাকে তবে আমি এটি কল্পনা করতে পারি যে এটি বর্তমানে বিদ্যমান ".জাইন ()" পদ্ধতিটি যদি সম্ভব হয় তবে তার বাক্য গঠন রাখার চেষ্টা করবে। যদি তা হয়ে থাকে তবে আপনি যদি এতে মাইগ্রেশন করতে চান তবে প্যারামিটারগুলি পরিবর্তন না করে বা আপনার কোডটি ভেঙে ফিরতে বিভিন্ন প্রকারের বিষয়ে চিন্তা না করে আপনি কেবল নিজের ফাংশনগুলির নাম পরিবর্তন করতে পারেন।

আমি জেনারিকস, এক্সটেনশনগুলি, ফানক স্টেটমেন্ট এবং অন্যান্য বৈশিষ্ট্যগুলি সহ এখনও নতুন, তাই প্রতিক্রিয়া অবশ্যই স্বাগত।

সম্পাদনা করুন: আমার কোড নিয়ে সমস্যা আছে তা বুঝতে আমার বেশি সময় । আমি লিনকিউপ্যাডে একটি .ডাম্প () করছিলাম এবং রিটার্নের ধরণটি দেখছিলাম। এটি কেবলমাত্র অনুমেয়যোগ্য ছিল, তাই আমি এটি মেলানোর চেষ্টা করেছি। তবে যখন আমি আসলে আমার এক্সটেনশনে একটি .Where () বা .Select () করেছি তখন আমি একটি ত্রুটি পেয়েছি: "'সিস্টেম সংগ্রহ I সুতরাং শেষ পর্যন্ত আমি .জাইন () এর ইনপুট সিনট্যাক্সের সাথে মেলতে সক্ষম হয়েছি, তবে ফেরতের আচরণ নয়।

সম্পাদনা: ফাংশনটির জন্য রিটার্ন টাইপের সাথে "ট্রিসল্ট" যুক্ত করা হয়েছে। মাইক্রোসফ্ট নিবন্ধ পড়ার সময় মিস করেছেন এবং অবশ্যই তা উপলব্ধি করে। এই ফিক্সটির সাথে, এখন মনে হচ্ছে রিটার্নের আচরণটি আমার লক্ষ্যগুলির সাথে সামঞ্জস্যপূর্ণ।


এই উত্তরের জন্য +2 পাশাপাশি মাইকেল স্যান্ডার্স। আমি দুর্ঘটনাক্রমে এটিকে ক্লিক করেছি এবং ভোটটি লক হয়ে গেছে। দুটি যোগ করুন।
তমুসজেরোয়েস

@ টিমাসজেআরয়েস, আমি কেবল কোড ফর্ম্যাটগুলি কিছুটা সম্পাদনা করতে গিয়েছিলাম। আমি বিশ্বাস করি কোনও সম্পাদনা করার পরে, আপনার নিজের ভোট পুনঃআসর্কের বিকল্প রয়েছে। ভাল লাগলে শট দিন।
pwilcox

তোমাকে অনেক ধন্যবাদ!
রোশনা ওমর

6

যেমনটি আপনি পেয়েছেন, লিন্কের "বাইরের যোগদান" কনস্ট্রাক্ট নেই। আপনার নিকটবর্তী ক্যোয়ারীটি ব্যবহার করে আপনি যে নিকটতমটি পেতে পারেন তা হ'ল একটি বাম বাহ্যিক যোগদান। এটিতে, আপনি লাস্ট নেম তালিকার এমন কোনও উপাদান যুক্ত করতে পারেন যা যোগদানের প্রতিনিধিত্ব করে না:

outerJoin = outerJoin.Concat(lastNames.Select(l=>new
                            {
                                id = l.ID,
                                firstname = String.Empty,
                                surname = l.Name
                            }).Where(l=>!outerJoin.Any(o=>o.id == l.id)));

2

আমি সেহের উত্তরটি পছন্দ করি তবে এটি স্থগিত কার্যকরকরণ ব্যবহার করে না (ইনপুট সিকোয়েন্সগুলি ToLookup এ কল করে আগ্রহের সাথে গণনা করা হয়)। সুতরাং লিনকিউ-টু-অবজেক্টের জন্য নেট নেট উত্সগুলি দেখার পরে আমি এটি নিয়ে এসেছি:

public static class LinqExtensions
{
    public static IEnumerable<TResult> FullOuterJoin<TLeft, TRight, TKey, TResult>(
        this IEnumerable<TLeft> left,
        IEnumerable<TRight> right,
        Func<TLeft, TKey> leftKeySelector,
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TKey, TResult> resultSelector,
        IEqualityComparer<TKey> comparator = null,
        TLeft defaultLeft = default(TLeft),
        TRight defaultRight = default(TRight))
    {
        if (left == null) throw new ArgumentNullException("left");
        if (right == null) throw new ArgumentNullException("right");
        if (leftKeySelector == null) throw new ArgumentNullException("leftKeySelector");
        if (rightKeySelector == null) throw new ArgumentNullException("rightKeySelector");
        if (resultSelector == null) throw new ArgumentNullException("resultSelector");

        comparator = comparator ?? EqualityComparer<TKey>.Default;
        return FullOuterJoinIterator(left, right, leftKeySelector, rightKeySelector, resultSelector, comparator, defaultLeft, defaultRight);
    }

    internal static IEnumerable<TResult> FullOuterJoinIterator<TLeft, TRight, TKey, TResult>(
        this IEnumerable<TLeft> left,
        IEnumerable<TRight> right,
        Func<TLeft, TKey> leftKeySelector,
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TKey, TResult> resultSelector,
        IEqualityComparer<TKey> comparator,
        TLeft defaultLeft,
        TRight defaultRight)
    {
        var leftLookup = left.ToLookup(leftKeySelector, comparator);
        var rightLookup = right.ToLookup(rightKeySelector, comparator);
        var keys = leftLookup.Select(g => g.Key).Union(rightLookup.Select(g => g.Key), comparator);

        foreach (var key in keys)
            foreach (var leftValue in leftLookup[key].DefaultIfEmpty(defaultLeft))
                foreach (var rightValue in rightLookup[key].DefaultIfEmpty(defaultRight))
                    yield return resultSelector(leftValue, rightValue, key);
    }
}

এই প্রয়োগের নিম্নলিখিত গুরুত্বপূর্ণ বৈশিষ্ট্য রয়েছে:

  • স্থগিত কার্যকর, আউটপুট ক্রম গণনা করার পূর্বে ইনপুট ক্রমগুলি গণনা করা হবে না।
  • কেবলমাত্র একবারে ইনপুট সিক্যুয়েন্সগুলি গণনা করে।
  • ইনপুট সিকোয়েন্সের ক্রম সংরক্ষণ করে, এই অর্থে যে এটি বাম ক্রমের ক্রমে এবং তার পরে ডানদিকে (বাম অনুক্রমের কীগুলির জন্য উপস্থিত নয়) ক্রমানুসারে টিপলস দেবে।

এই বৈশিষ্ট্যগুলি গুরুত্বপূর্ণ, কারণ তারা হ'ল ফুলআউটারজয়িনে নতুন কেউ যা প্রত্যাশা করবে LIN


এটি ইনপুট সিকোয়েন্সগুলির ক্রম সংরক্ষণ করে না: লুকআপ গ্যারান্টি দেয় না, সুতরাং এই পূর্বাভাস বাম দিকের কিছু ক্রমের মধ্যে অঙ্কিত হবে, তারপরে ডান দিকের কিছু ক্রম বাম দিকে উপস্থিত হবে না। তবে উপাদানগুলির সম্পর্কিত সম্পর্কিত ক্রম সংরক্ষণ করা হয় না।
ইভান ড্যানিলভ

@ ইভানডানিলভ আপনি ঠিক বলেছেন যে এটি আসলে চুক্তিতে নেই। ToLookup এর বাস্তবায়ন, তবে, Enumerable.cs এ একটি অভ্যন্তরীণ লুকআপ ক্লাস ব্যবহার করে যা সন্নিবেশ-অর্ডারযুক্ত লিঙ্কযুক্ত তালিকায় গ্রুপিং রাখে এবং তাদের মাধ্যমে পুনরাবৃত্তি করতে এই তালিকাটি ব্যবহার করে। সুতরাং বর্তমান। নেট সংস্করণে, অর্ডার নিশ্চিত হয়েছে, তবে যেহেতু এমএস দুর্ভাগ্যক্রমে এটি নথিভুক্ত করেছে না, তারা পরবর্তী সংস্করণগুলিতে এটি পরিবর্তন করতে পারে।
সেরেন বোইসেন

আমি উইন 8.1 এ .NET 4.5.1 এ চেষ্টা করেছি এবং এটি অর্ডার সংরক্ষণ করে না।
ইভান ড্যানিলভ

1
"..পরে ইনপুট ক্রমগুলি ToLookup এ কল করে উত্সাহিত করা হয়েছে"। তবে আপনার বাস্তবায়ন হুবহু একই রকম .. সসীম-রাষ্ট্রের মেশিনে ব্যয়ের কারণে ফলন এখানে খুব বেশি দেয় না।
pkuderov

4
ফলাফলের প্রথম উপাদানটির জন্য অনুরোধ করা হলে লুকআপ কলগুলি করা হয়, এবং পুনরুক্তিটি তৈরি করার সময় নয়। স্থগিতাদেশ কার্যকর হ'ল এর অর্থ। আপনি আরও একবার ইনপুট সেটটির গণনা স্থগিত করতে পারতেন, বাম এনুমিউরেবলটিকে একবার লুপআপে রূপান্তরিত না করে সরাসরি পুনরাবৃত্ত করে, অতিরিক্ত বেনিফিটের ফলে বাম সেটটির ক্রম সংরক্ষণ করা যায়।
রল্ফ

2

আমি এটি পৃথক উত্তর হিসাবে যুক্ত করার সিদ্ধান্ত নিয়েছি কারণ এটি যথেষ্ট পরীক্ষিত নয় আমি ইতিবাচক নই। এই একটি পুনরায় বাস্তবায়ন FullOuterJoinমূলত একটি সরলীকৃত, এর কাস্টমাইজড সংস্করণ ব্যবহার পদ্ধতি LINQKit Invoke/ Expandজন্য Expressionযাতে এটি সত্তা ফ্রেমওয়ার্ক কাজ করা উচিত। এটি আমার পূর্ববর্তী উত্তরের মতো প্রায় একই ধরণের কোনও ব্যাখ্যা নেই।

public static class Ext {
    private static Expression<Func<TP, TC, TResult>> CastSMBody<TP, TC, TResult>(LambdaExpression ex, TP unusedP, TC unusedC, TResult unusedRes) => (Expression<Func<TP, TC, TResult>>)ex;

    public static IQueryable<TResult> LeftOuterJoin<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector) {

        // (lrg,r) => resultSelector(lrg.left, r)
        var sampleAnonLR = new { left = default(TLeft), rightg = default(IEnumerable<TRight>) };
        var parmP = Expression.Parameter(sampleAnonLR.GetType(), "lrg");
        var parmC = Expression.Parameter(typeof(TRight), "r");
        var argLeft = Expression.PropertyOrField(parmP, "left");
        var newleftrs = CastSMBody(Expression.Lambda(resultSelector.Apply(argLeft, parmC), parmP, parmC), sampleAnonLR, default(TRight), default(TResult));

        return leftItems.GroupJoin(rightItems, leftKeySelector, rightKeySelector, (left, rightg) => new { left, rightg }).SelectMany(r => r.rightg.DefaultIfEmpty(), newleftrs);
    }

    public static IQueryable<TResult> RightOuterJoin<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector) {

        // (lgr,l) => resultSelector(l, lgr.right)
        var sampleAnonLR = new { leftg = default(IEnumerable<TLeft>), right = default(TRight) };
        var parmP = Expression.Parameter(sampleAnonLR.GetType(), "lgr");
        var parmC = Expression.Parameter(typeof(TLeft), "l");
        var argRight = Expression.PropertyOrField(parmP, "right");
        var newrightrs = CastSMBody(Expression.Lambda(resultSelector.Apply(parmC, argRight), parmP, parmC), sampleAnonLR, default(TLeft), default(TResult));

        return rightItems.GroupJoin(leftItems, rightKeySelector, leftKeySelector, (right, leftg) => new { leftg, right })
                         .SelectMany(l => l.leftg.DefaultIfEmpty(), newrightrs);
    }

    private static Expression<Func<TParm, TResult>> CastSBody<TParm, TResult>(LambdaExpression ex, TParm unusedP, TResult unusedRes) => (Expression<Func<TParm, TResult>>)ex;

    public static IQueryable<TResult> RightAntiSemiJoin<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector) where TLeft : class where TRight : class where TResult : class {

        // newrightrs = lgr => resultSelector(default(TLeft), lgr.right)
        var sampleAnonLgR = new { leftg = (IEnumerable<TLeft>)null, right = default(TRight) };
        var parmLgR = Expression.Parameter(sampleAnonLgR.GetType(), "lgr");
        var argLeft = Expression.Constant(default(TLeft), typeof(TLeft));
        var argRight = Expression.PropertyOrField(parmLgR, "right");
        var newrightrs = CastSBody(Expression.Lambda(resultSelector.Apply(argLeft, argRight), parmLgR), sampleAnonLgR, default(TResult));

        return rightItems.GroupJoin(leftItems, rightKeySelector, leftKeySelector, (right, leftg) => new { leftg, right }).Where(lgr => !lgr.leftg.Any()).Select(newrightrs);
    }

    public static IQueryable<TResult> FullOuterJoin<TLeft, TRight, TKey, TResult>(
        this IQueryable<TLeft> leftItems,
        IQueryable<TRight> rightItems,
        Expression<Func<TLeft, TKey>> leftKeySelector,
        Expression<Func<TRight, TKey>> rightKeySelector,
        Expression<Func<TLeft, TRight, TResult>> resultSelector)  where TLeft : class where TRight : class where TResult : class {

        return leftItems.LeftOuterJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector).Concat(leftItems.RightAntiSemiJoin(rightItems, leftKeySelector, rightKeySelector, resultSelector));
    }

    public static Expression Apply(this LambdaExpression e, params Expression[] args) {
        var b = e.Body;

        foreach (var pa in e.Parameters.Cast<ParameterExpression>().Zip(args, (p, a) => (p, a))) {
            b = b.Replace(pa.p, pa.a);
        }

        return b.PropagateNull();
    }

    public static Expression Replace(this Expression orig, Expression from, Expression to) => new ReplaceVisitor(from, to).Visit(orig);
    public class ReplaceVisitor : System.Linq.Expressions.ExpressionVisitor {
        public readonly Expression from;
        public readonly Expression to;

        public ReplaceVisitor(Expression _from, Expression _to) {
            from = _from;
            to = _to;
        }

        public override Expression Visit(Expression node) => node == from ? to : base.Visit(node);
    }

    public static Expression PropagateNull(this Expression orig) => new NullVisitor().Visit(orig);
    public class NullVisitor : System.Linq.Expressions.ExpressionVisitor {
        public override Expression Visit(Expression node) {
            if (node is MemberExpression nme && nme.Expression is ConstantExpression nce && nce.Value == null)
                return Expression.Constant(null, nce.Type.GetMember(nme.Member.Name).Single().GetMemberType());
            else
                return base.Visit(node);
        }
    }

    public static Type GetMemberType(this MemberInfo member) {
        switch (member) {
            case FieldInfo mfi:
                return mfi.FieldType;
            case PropertyInfo mpi:
                return mpi.PropertyType;
            case EventInfo mei:
                return mei.EventHandlerType;
            default:
                throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", nameof(member));
        }
    }
}

নেটমেজ, চিত্তাকর্ষক কোডিং! আমি যখন এটি একটি সাধারণ উদাহরণ দিয়ে চালিত করি এবং [নালভিসর.ভিজিট (..) যখন [বেস.ভিজিট (নোড)] তে ডাকে তখন এটি একটি [সিস্টেম.আরগমেন্ট এক্সপেশন: আর্গুমেন্টের প্রকার মেলে না]। কোনটি সত্য, যেহেতু আমি একটি [গাইড] টিকি ব্যবহার করছি এবং কোনও সময়ে নাল দর্শনার্থী একটি [গাইড?] টাইপ আশা করে। হতে পারে আমি কিছু মিস করছি আমি একটি সংক্ষিপ্ত উদাহরণ আছে EF 6.4.4 এর জন্য কোডেড। আমি আপনার সাথে এই কোডটি কীভাবে ভাগ করতে পারি তা আমাকে জানান। ধন্যবাদ!
ট্রোনচো

@ ট্র্যাঞ্চো আমি সাধারণত পরীক্ষার জন্য লিনিকপ্যাড ব্যবহার করি, সুতরাং EF 6 সহজে হয় না। base.Visit(node)যে গাছটি কেবল পুনরুত্থিত হয় সে হিসাবে একটি ব্যতিক্রম ছোঁড়া উচিত নয়। আমি বেশ কয়েকটি কোড শেয়ারিং পরিষেবা অ্যাক্সেস করতে পারি, তবে কোনও পরীক্ষা ডেটাবেস সেটআপ করি না। যদিও এটি আমার লিনকিউ থেকে এসকিউএল পরীক্ষার বিরুদ্ধে চালানো ভাল মনে হচ্ছে।
নেটমেজ

@ ট্র্যাঙ্কো কি সম্ভব যে আপনি Guidকী এবং Guid?বৈদেশিক চাবিতে যোগ দিচ্ছেন?
নেটমেজ

আমি লিনকপ্যাডটিও পরীক্ষার জন্য ব্যবহার করছি। আমার জিজ্ঞাসাটি আর্গুমেন্টএক্সেপশনকে ছুঁড়ে ফেলেছে তাই আমি এটি [। নেট ফ্রেমওয়ার্ক 4.7.1] এবং সর্বশেষতম এএফ 6 এর উপরে VS2019 এ ডিবাগ করার সিদ্ধান্ত নিয়েছি There সেখানে আমি আসল সমস্যাটি সনাক্ত করতে পেরেছি। আপনার কোডটি পরীক্ষা করার জন্য, আমি একই [ব্যক্তি] টেবিল থেকে উত্পন্ন দুটি পৃথক ডেটা সেট তৈরি করছি। আমি উভয় সেট ফিল্টার করি যাতে কিছু রেকর্ড প্রতিটি সেটের জন্য স্বতন্ত্র এবং কিছু দুটি সেটে বিদ্যমান থাকে। [পার্সোনআইডি] হ'ল একটি [প্রাথমিক কী] গাইড (সি #) / ইউনিকডফিকার (স্কেলসার্ভার) এবং কোনও সেট নকল [পার্সোনআইডি] মান উত্পন্ন করে না। ভাগ করা কোড: github.com/Troncho/EF_FullOuterJoin
ট্রানচো

1

উভয় ইনপুটগুলির জন্য একটি ইন-মেমরি স্ট্রিমিং গণনা সম্পাদন করে এবং প্রতিটি সারির জন্য নির্বাচককে অনুরোধ করে। বর্তমান পুনরাবৃত্তির সাথে যদি কোনও সম্পর্ক নেই, তবে নির্বাচকদের একটি আর্গুমেন্ট বাতিল হবে

উদাহরণ:

   var result = left.FullOuterJoin(
         right, 
         x=>left.Key, 
         x=>right.Key, 
         (l,r) => new { LeftKey = l?.Key, RightKey=r?.Key });
  • পারস্পরিক সম্পর্ক প্রকারের জন্য একটি আইসি কম্পিউটারে প্রয়োজন, যদি সরবরাহ না করা হয় তবে তুলনা করুন ডিফল্ট ব্যবহার করুন।

  • ইনপুট এনামিউরেবলসগুলিতে 'অর্ডারবাই' প্রয়োগ করা দরকার

    /// <summary>
    /// Performs a full outer join on two <see cref="IEnumerable{T}" />.
    /// </summary>
    /// <typeparam name="TLeft"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <typeparam name="TRight"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="left"></param>
    /// <param name="right"></param>
    /// <param name="leftKeySelector"></param>
    /// <param name="rightKeySelector"></param>
    /// <param name="selector">Expression defining result type</param>
    /// <param name="keyComparer">A comparer if there is no default for the type</param>
    /// <returns></returns>
    [System.Diagnostics.DebuggerStepThrough]
    public static IEnumerable<TResult> FullOuterJoin<TLeft, TRight, TValue, TResult>(
        this IEnumerable<TLeft> left,
        IEnumerable<TRight> right,
        Func<TLeft, TValue> leftKeySelector,
        Func<TRight, TValue> rightKeySelector,
        Func<TLeft, TRight, TResult> selector,
        IComparer<TValue> keyComparer = null)
        where TLeft: class
        where TRight: class
        where TValue : IComparable
    {
    
        keyComparer = keyComparer ?? Comparer<TValue>.Default;
    
        using (var enumLeft = left.OrderBy(leftKeySelector).GetEnumerator())
        using (var enumRight = right.OrderBy(rightKeySelector).GetEnumerator())
        {
    
            var hasLeft = enumLeft.MoveNext();
            var hasRight = enumRight.MoveNext();
            while (hasLeft || hasRight)
            {
    
                var currentLeft = enumLeft.Current;
                var valueLeft = hasLeft ? leftKeySelector(currentLeft) : default(TValue);
    
                var currentRight = enumRight.Current;
                var valueRight = hasRight ? rightKeySelector(currentRight) : default(TValue);
    
                int compare =
                    !hasLeft ? 1
                    : !hasRight ? -1
                    : keyComparer.Compare(valueLeft, valueRight);
    
                switch (compare)
                {
                    case 0:
                        // The selector matches. An inner join is achieved
                        yield return selector(currentLeft, currentRight);
                        hasLeft = enumLeft.MoveNext();
                        hasRight = enumRight.MoveNext();
                        break;
                    case -1:
                        yield return selector(currentLeft, default(TRight));
                        hasLeft = enumLeft.MoveNext();
                        break;
                    case 1:
                        yield return selector(default(TLeft), currentRight);
                        hasRight = enumRight.MoveNext();
                        break;
                }
            }
    
        }
    
    }

1
জিনিসগুলিকে "স্ট্রিমিং" করার একটি বীরত্বপূর্ণ প্রচেষ্টা। দুঃখজনকভাবে, সমস্ত লাভ প্রথম ধাপে হারিয়ে যায়, যেখানে আপনি OrderByউভয় মূল অনুমানের উপর সঞ্চালন করেন। OrderByসুস্পষ্ট কারণে পুরো ক্রমটি বাফার করে
শেে

@ আপনি লিনক টু অবজেক্টের পক্ষে অবশ্যই সঠিক। যদি আইনিউবারেবল <T> আইকিউয়েরেবল হয় তবে <T> উত্সটি সাজানো উচিত - তবে পরীক্ষার সময় নেই। আমি যদি এই সম্পর্কে ভুল হয়ে থাকি তবে কেবল আইকুয়্যারেবল <T> এর সাথে আইনিউবারেবল <T> ইনপুটটি প্রতিস্থাপন করা উচিত উত্স / ডাটাবেস অনুসারে বাছাই করা।
জেমস কারাডোক-ডেভিস

1

পরিস্থিতিটির জন্য আমার পরিষ্কার সমাধান যে চাবিকাঠি দুটি ক্ষেত্রেই অনন্য:

 private static IEnumerable<TResult> FullOuterJoin<Ta, Tb, TKey, TResult>(
            IEnumerable<Ta> a, IEnumerable<Tb> b,
            Func<Ta, TKey> key_a, Func<Tb, TKey> key_b,
            Func<Ta, Tb, TResult> selector)
        {
            var alookup = a.ToLookup(key_a);
            var blookup = b.ToLookup(key_b);
            var keys = new HashSet<TKey>(alookup.Select(p => p.Key));
            keys.UnionWith(blookup.Select(p => p.Key));
            return keys.Select(key => selector(alookup[key].FirstOrDefault(), blookup[key].FirstOrDefault()));
        }

সুতরাং

    var ax = new[] {
        new { id = 1, first_name = "ali" },
        new { id = 2, first_name = "mohammad" } };
    var bx = new[] {
        new { id = 1, last_name = "rezaei" },
        new { id = 3, last_name = "kazemi" } };

    var list = FullOuterJoin(ax, bx, a => a.id, b => b.id, (a, b) => "f: " + a?.first_name + " l: " + b?.last_name).ToArray();

আউটপুট:

f: ali l: rezaei
f: mohammad l:
f:  l: kazemi

0

দুই বা ততোধিক টেবিলের জন্য পূর্ণ বাহ্যিক জোড়: প্রথমে আপনি যে কলামটিতে যোগ দিতে চান তা বের করুন।

var DatesA = from A in db.T1 select A.Date; 
var DatesB = from B in db.T2 select B.Date; 
var DatesC = from C in db.T3 select C.Date;            

var Dates = DatesA.Union(DatesB).Union(DatesC); 

তারপরে নিষ্ক্রিয় কলাম এবং প্রধান সারণীগুলির মধ্যে বাম বাহিরের জোড় ব্যবহার করুন।

var Full_Outer_Join =

(from A in Dates
join B in db.T1
on A equals B.Date into AB 

from ab in AB.DefaultIfEmpty()
join C in db.T2
on A equals C.Date into ABC 

from abc in ABC.DefaultIfEmpty()
join D in db.T3
on A equals D.Date into ABCD

from abcd in ABCD.DefaultIfEmpty() 
select new { A, ab, abc, abcd })
.AsEnumerable();

0

আমি সম্ভবত 6 বছর আগে একটি অ্যাপ্লিকেশনটির জন্য এই এক্সটেনশন ক্লাসটি লিখেছি এবং এটি সমস্যা ছাড়াই অনেক সমাধানে ব্যবহার করে আসছি। আশা করি এটা সাহায্য করবে.

সম্পাদনা: আমি লক্ষ্য করেছি যে কেউ কেউ কীভাবে একটি এক্সটেনশন ক্লাস ব্যবহার করবেন তা জানেন না।

এই এক্সটেনশান ক্লাসটি ব্যবহার করতে, কেবল জাইনেক্সট ব্যবহার করে নিম্নলিখিত রেখাটি যুক্ত করে আপনার শ্রেণিতে এর নেমস্পেসটি উল্লেখ করুন;

^ এটি আপনাকে ব্যবহার করতে পারে এমন যে কোনও অপ্রয়োজনীয় অবজেক্ট সংগ্রহের ক্ষেত্রে এক্সটেনশন ফাংশনগুলির ইন্টেলিজেন্স দেখার অনুমতি দেয়।

আশাকরি এটা সাহায্য করবে. এটি এখনও পরিষ্কার না হলে আমাকে জানান, এবং আমি কীভাবে এটি ব্যবহার করব সে সম্পর্কে একটি নমুনা উদাহরণ লিখব।

এখন এখানে ক্লাস:

namespace joinext
{    
public static class JoinExtensions
    {
        public static IEnumerable<TResult> FullOuterJoin<TOuter, TInner, TKey, TResult>(
            this IEnumerable<TOuter> outer,
            IEnumerable<TInner> inner,
            Func<TOuter, TKey> outerKeySelector,
            Func<TInner, TKey> innerKeySelector,
            Func<TOuter, TInner, TResult> resultSelector)
            where TInner : class
            where TOuter : class
        {
            var innerLookup = inner.ToLookup(innerKeySelector);
            var outerLookup = outer.ToLookup(outerKeySelector);

            var innerJoinItems = inner
                .Where(innerItem => !outerLookup.Contains(innerKeySelector(innerItem)))
                .Select(innerItem => resultSelector(null, innerItem));

            return outer
                .SelectMany(outerItem =>
                {
                    var innerItems = innerLookup[outerKeySelector(outerItem)];

                    return innerItems.Any() ? innerItems : new TInner[] { null };
                }, resultSelector)
                .Concat(innerJoinItems);
        }


        public static IEnumerable<TResult> LeftJoin<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,
                (o, i) =>
                    new { o = o, i = i.DefaultIfEmpty() })
                    .SelectMany(m => m.i.Select(inn =>
                        resultSelector(m.o, inn)
                        ));

        }



        public static IEnumerable<TResult> RightJoin<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 inner.GroupJoin(
                outer,
                innerKeySelector,
                outerKeySelector,
                (i, o) =>
                    new { i = i, o = o.DefaultIfEmpty() })
                    .SelectMany(m => m.o.Select(outt =>
                        resultSelector(outt, m.i)
                        ));

        }

    }
}

1
দুর্ভাগ্যক্রমে, মনে হচ্ছে এটির ফাংশনটি SelectManyএকটি লিনিক্যু 2 এসকিউএল-যোগ্য এক্সপ্রেশন ট্রিতে রূপান্তরিত করা যায় না, মনে হয়।
বা ম্যাপার

edc65। আমি জানি আপনি যদি ইতিমধ্যে এটি করেন তবে এটি একটি নির্বোধ প্রশ্ন হতে পারে। তবে কেবলমাত্র (যেমন আমি দেখেছি যে কেউ জানেন না), আপনাকে কেবল নেমস্পেসের জাইনেক্সট উল্লেখ করতে হবে।
এইচ 7 ও

বা ম্যাপার, আপনি কী ধরণের সংগ্রহ কাজ করতে চান তা সম্পর্কে আমাকে জানান। এটি যেকোনও মূল সংখ্যার সাথে কাজ করতে হবে
এইচ 7 ও

0

আমি মনে করি যে লিনকিউ যোগদানের ক্লজটি এই সমস্যার সঠিক সমাধান নয়, কারণ যোগদানের ক্লজটির উদ্দেশ্য এই কাজের সমাধানের জন্য প্রয়োজনীয়ভাবে তথ্য সংগ্রহ করা নয় isn't আলাদা আলাদা সংগ্রহগুলিতে মার্জ করার কোডটি খুব জটিল হয়ে ওঠে, সম্ভবত এটি শেখার উদ্দেশ্যে ঠিক আছে তবে বাস্তব প্রয়োগগুলির জন্য নয়। এই সমস্যাটিকে কীভাবে সমাধান করবেন তার একটি উপায় নীচের কোডে রয়েছে:

class Program
{
    static void Main(string[] args)
    {
        List<FirstName> firstNames = new List<FirstName>();
        firstNames.Add(new FirstName { ID = 1, Name = "John" });
        firstNames.Add(new FirstName { ID = 2, Name = "Sue" });

        List<LastName> lastNames = new List<LastName>();
        lastNames.Add(new LastName { ID = 1, Name = "Doe" });
        lastNames.Add(new LastName { ID = 3, Name = "Smith" });

        HashSet<int> ids = new HashSet<int>();
        foreach (var name in firstNames)
        {
            ids.Add(name.ID);
        }
        foreach (var name in lastNames)
        {
            ids.Add(name.ID);
        }
        List<FullName> fullNames = new List<FullName>();
        foreach (int id in ids)
        {
            FullName fullName = new FullName();
            fullName.ID = id;
            FirstName firstName = firstNames.Find(f => f.ID == id);
            fullName.FirstName = firstName != null ? firstName.Name : string.Empty;
            LastName lastName = lastNames.Find(l => l.ID == id);
            fullName.LastName = lastName != null ? lastName.Name : string.Empty;
            fullNames.Add(fullName);
        }
    }
}
public class FirstName
{
    public int ID;

    public string Name;
}

public class LastName
{
    public int ID;

    public string Name;
}
class FullName
{
    public int ID;

    public string FirstName;

    public string LastName;
}

পরিবর্তে হ্যাশসেট গঠনের জন্য যদি সত্য সংগ্রহগুলি বড় হয় তবে ফোরচ লুপগুলি নীচের কোডটি ব্যবহার করা যেতে পারে:

List<int> firstIds = firstNames.Select(f => f.ID).ToList();
List<int> LastIds = lastNames.Select(l => l.ID).ToList();
HashSet<int> ids = new HashSet<int>(firstIds.Union(LastIds));//Only unique IDs will be included in HashSet

0

আকর্ষণীয় পোস্টের জন্য আপনাকে সবাইকে ধন্যবাদ!

আমি কোডটি সংশোধন করেছি কারণ আমার ক্ষেত্রে আমার প্রয়োজন ছিল

  • একটি ব্যক্তিগতকৃত যোগদান
  • একটি ব্যক্তিগতকৃত ইউনিয়ন স্বতন্ত্র তুলনামূলক

যাদের আগ্রহী তাদের জন্য এটি আমার সংশোধিত কোড (ভিবিতে, দুঃখিত)

    Module MyExtensions
        <Extension()>
        Friend Function FullOuterJoin(Of TA, TB, TResult)(ByVal a As IEnumerable(Of TA), ByVal b As IEnumerable(Of TB), ByVal joinPredicate As Func(Of TA, TB, Boolean), ByVal projection As Func(Of TA, TB, TResult), ByVal comparer As IEqualityComparer(Of TResult)) As IEnumerable(Of TResult)
            Dim joinL =
                From xa In a
                From xb In b.Where(Function(x) joinPredicate(xa, x)).DefaultIfEmpty()
                Select projection(xa, xb)
            Dim joinR =
                From xb In b
                From xa In a.Where(Function(x) joinPredicate(x, xb)).DefaultIfEmpty()
                Select projection(xa, xb)
            Return joinL.Union(joinR, comparer)
        End Function
    End Module

    Dim fullOuterJoin = lefts.FullOuterJoin(
        rights,
        Function(left, right) left.Code = right.Code And (left.Amount [...] Or left.Description.Contains [...]),
        Function(left, right) New CompareResult(left, right),
        New MyEqualityComparer
    )

    Public Class MyEqualityComparer
        Implements IEqualityComparer(Of CompareResult)

        Private Function GetMsg(obj As CompareResult) As String
            Dim msg As String = ""
            msg &= obj.Code & "_"
            [...]
            Return msg
        End Function

        Public Overloads Function Equals(x As CompareResult, y As CompareResult) As Boolean Implements IEqualityComparer(Of CompareResult).Equals
            Return Me.GetMsg(x) = Me.GetMsg(y)
        End Function

        Public Overloads Function GetHashCode(obj As CompareResult) As Integer Implements IEqualityComparer(Of CompareResult).GetHashCode
            Return Me.GetMsg(obj).GetHashCode
        End Function
    End Class

0

তবুও আরও একটি সম্পূর্ণ বাহ্যিক যোগদান

অন্যান্য প্রস্তাবগুলির সরলতা এবং পাঠযোগ্যতার সাথে যেমন খুশি ছিল না, আমি এটি দিয়ে শেষ করেছি:

এটিতে প্রিটিশনটি দ্রুত হওয়ার দরকার নেই (২০০০ মিটার সিপিইউতে ১০০০ * ১০০০ তে যোগ দিতে প্রায় 800 এমএস): ২.৪ গিগাহার্টজ / ২ কোরস)। আমার কাছে এটি কেবল একটি কমপ্যাক্ট এবং নৈমিত্তিক পূর্ণ বাইরের যোগদান join

এটি একটি এসকিউএল সম্পূর্ণ আউট জয়েন (ডুপ্লিকেট সংরক্ষণ) হিসাবে একই কাজ করে

চিয়ার্স ;-)

using System;
using System.Collections.Generic;
using System.Linq;
namespace NS
{
public static class DataReunion
{
    public static List<Tuple<T1, T2>> FullJoin<T1, T2, TKey>(List<T1> List1, Func<T1, TKey> KeyFunc1, List<T2> List2, Func<T2, TKey> KeyFunc2)
    {
        List<Tuple<T1, T2>> result = new List<Tuple<T1, T2>>();

        Tuple<TKey, T1>[] identifiedList1 = List1.Select(_ => Tuple.Create(KeyFunc1(_), _)).OrderBy(_ => _.Item1).ToArray();
        Tuple<TKey, T2>[] identifiedList2 = List2.Select(_ => Tuple.Create(KeyFunc2(_), _)).OrderBy(_ => _.Item1).ToArray();

        identifiedList1.Where(_ => !identifiedList2.Select(__ => __.Item1).Contains(_.Item1)).ToList().ForEach(_ => {
            result.Add(Tuple.Create<T1, T2>(_.Item2, default(T2)));
        });

        result.AddRange(
            identifiedList1.Join(identifiedList2, left => left.Item1, right => right.Item1, (left, right) => Tuple.Create<T1, T2>(left.Item2, right.Item2)).ToList()
        );

        identifiedList2.Where(_ => !identifiedList1.Select(__ => __.Item1).Contains(_.Item1)).ToList().ForEach(_ => {
            result.Add(Tuple.Create<T1, T2>(default(T1), _.Item2));
        });

        return result;
    }
}
}

ধারণাটি হয়

  1. প্রদত্ত কী ফাংশন নির্মাতাদের উপর ভিত্তি করে আইডিগুলি তৈরি করুন
  2. প্রক্রিয়া শুধুমাত্র বাম আইটেম
  3. অভ্যন্তরীণ যোগদান প্রক্রিয়া
  4. সঠিক আইটেম প্রক্রিয়া

এখানে একটি সংক্ষিপ্ত পরীক্ষা রয়েছে যা এর সাথে চলে:

এটি প্রত্যাশার মতো আচরণ করে তা ম্যানুয়ালি যাচাই করতে শেষে একটি ব্রেক পয়েন্ট রাখুন

using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NS;

namespace Tests
{
[TestClass]
public class DataReunionTest
{
    [TestMethod]
    public void Test()
    {
        List<Tuple<Int32, Int32, String>> A = new List<Tuple<Int32, Int32, String>>();
        List<Tuple<Int32, Int32, String>> B = new List<Tuple<Int32, Int32, String>>();

        Random rnd = new Random();

        /* Comment the testing block you do not want to run
        /* Solution to test a wide range of keys*/

        for (int i = 0; i < 500; i += 1)
        {
            A.Add(Tuple.Create(rnd.Next(1, 101), rnd.Next(1, 101), "A"));
            B.Add(Tuple.Create(rnd.Next(1, 101), rnd.Next(1, 101), "B"));
        }

        /* Solution for essential testing*/

        A.Add(Tuple.Create(1, 2, "B11"));
        A.Add(Tuple.Create(1, 2, "B12"));
        A.Add(Tuple.Create(1, 3, "C11"));
        A.Add(Tuple.Create(1, 3, "C12"));
        A.Add(Tuple.Create(1, 3, "C13"));
        A.Add(Tuple.Create(1, 4, "D1"));

        B.Add(Tuple.Create(1, 1, "A21"));
        B.Add(Tuple.Create(1, 1, "A22"));
        B.Add(Tuple.Create(1, 1, "A23"));
        B.Add(Tuple.Create(1, 2, "B21"));
        B.Add(Tuple.Create(1, 2, "B22"));
        B.Add(Tuple.Create(1, 2, "B23"));
        B.Add(Tuple.Create(1, 3, "C2"));
        B.Add(Tuple.Create(1, 5, "E2"));

        Func<Tuple<Int32, Int32, String>, Tuple<Int32, Int32>> key = (_) => Tuple.Create(_.Item1, _.Item2);

        var watch = System.Diagnostics.Stopwatch.StartNew();
        var res = DataReunion.FullJoin(A, key, B, key);
        watch.Stop();
        var elapsedMs = watch.ElapsedMilliseconds;
        String aser = JToken.FromObject(res).ToString(Formatting.Indented);
        Console.Write(elapsedMs);
    }
}

}


-4

আমি এই লিনাক এক্সপ্রেশনকে সত্যিই ঘৃণা করি, এজন্য এসকিউএল বিদ্যমান:

select isnull(fn.id, ln.id) as id, fn.firstname, ln.lastname
   from firstnames fn
   full join lastnames ln on ln.id=fn.id

এটি ডাটাবেসে স্কয়ার ভিউ হিসাবে তৈরি করুন এবং সত্তা হিসাবে এটি আমদানি করুন।

অবশ্যই, (স্বতন্ত্র) বাম এবং ডান সংযোজন এটিও তৈরি করবে তবে এটি নির্বোধ।


11
কেন কেবলমাত্র যথাসম্ভব বিমূর্ততা ফেলে এবং মেশিন কোডে এটি করবেন না? (ইঙ্গিত: কারণ উচ্চতর আদেশ বিমূর্ততা প্রোগ্রামারটির জন্য জীবনকে সহজ করে তোলে)। এটি প্রশ্নের উত্তর দেয় না এবং আমার কাছে লিনকিউর বিরুদ্ধে অভিমানের মতো আরও বেশি দেখে।
ব্যয়কারী

8
কে বলেছে ডেটাবেস থেকে ডেটা আসে?
ব্যবহারকারী 247702

1
অবশ্যই এটি ডাটাবেস, প্রশ্নে "বাইরের যোগদান" শব্দ আছে :) google.cz/search?q=outer+join
মিলান Švec

1
আমি বুঝতে পারি যে এটি "পুরানো ফ্যাশন" সমাধান, তবে ডাউনভোটিংয়ের আগে এর জটিলতার সাথে অন্যান্য সমাধানগুলির সাথে তুলনা করুন :) গৃহীত গৃহীত ব্যতীত এটি অবশ্যই সঠিক।
মিলান Švec

অবশ্যই এটি ডাটাবেস হতে পারে বা নাও হতে পারে। আমি মেমরির তালিকার মধ্যে একটি বাহ্যিক
সংযুক্তির
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.