SORU
30 Mart 2011, ÇARŞAMBA


SERİ - Tam Dış Birleşim

İnsanların KİMLİĞİ listesini ve ilk ismim var, ve insanların bir listesini KİMLİĞİ ve soyadı. Bazı insanlar ilk bir adı yok ve soyadı yok; iki listeyi tam dış birleşim yapmak istiyorum.

Aşağıdaki listeler:

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

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

Oluşturmak:

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

Ben yeni bu SERİ (affedin beni eğer oluyorum topal) ve buldum epeyce çözümler için 'SERİ Dış Birleşimler' tüm bakmak oldukça benzer, ama gerçekten görünüyor sol dış birleşimler.

Benim girişimler şu ana kadar böyle bir şey gidin:

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;
}

Ama bu döndürür:

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

Neyi yanlış yapıyorum?

CEVAP
21 Kasım 2012, ÇARŞAMBA


Güncelleme 1: gerçekten genelleştirilmiş uzatma yöntemi FullOuterJoin . sağlama Güncelleme 2: isteğe bağlı olarak bir özel anahtar türü için IEqualityComparer " olarak anılmaktadır

EditEklendi FullOuterGroupJoin (ideone). GetOuter<> uygulama, bu olabilir, ama 'yüksek düzey' kod, kenar kanama değil, şu anda optimize edilmiş. hedef daha bir kısmı daha az ölçülebilir yapıyorum yeniden

Yaşamanıza bakınhttp://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);
}

Parmak izi çıktı:

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

Ayrıca varsayılan kaynağı olabilir: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)" }
        )

Baskı:

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

Terimlerin açıklaması:

Katılacak bir dönem ilişkisel veritabanı tasarımı ödünç:

  • Birkatılınb elementler vardır kadar a öğeleri tekrar edecektirilgili anahtar ile(örn: b boş) ise hiçbir şey.Veritabanı lingo bu inner (equi)join çağırır.
  • Birdış birleşimbir eleman için bir içeririlgili elemanvar b. (örn: eğer b boş olsa bile sonuçlar).Bu genellikle left join olarak adlandırılır.
  • Birtam dış birleşimiçerir a kayıtlarıyanı sıra beğerhiçbir karşılık gelen öğediğer var. (a boş olsa bile sonuçları gibi)

Bir şey değilgenellikleİLİŞKİSEL görülür bir gruba katılmak[1]:

  • Birgruba katılmakyukarıda açıklanan, ., aynı işi yapar gibi ^strong>amabirden fazla b ilgili a dan öğelerini yerinegruplarkarşılık gelen tuşları ile kayıtları. Bu '' kayıtları, ortak bir anahtara bağlı. katıldı numaralandırma ile istediğiniz zaman genellikle daha uygundur

Aynı zamanda bazı genel arka plan açıklamalar içeren GroupJoin bkz.


[1](Oracle ve MSSQL bunun için özel uzantıları var sanırım)

Tam kodu

'Bırak-' bunun için Uzantısı sınıf . bir genelleştirilmiş

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;
    }
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • HTC

    HTC

    12 Ocak 2006
  • Peter Sharp

    Peter Sharp

    11 ŞUBAT 2013
  • Sorikan

    Sorikan

    3 ŞUBAT 2008