簡體   English   中英

LINQ合並兩個列表(復合鍵上的完整外部聯接)

[英]LINQ merging two lists(full outer join on composite keys)

我有兩個清單

 IEnumerable<Citrus> grapefruit = citrusList.Where(x => x.IsSmall == false);
 IEnumerable<Citrus> tangerines = citrusList.Where(x => x.IsSmall == true);

我想將所有柑橘類水果放入一個PackingContainer中,但首先要從柚子和橘子中制作橘子-柚子和橘子的混合物-橘子=橘子,柑橘-風味=非常濃郁,柑橘紋理=顆粒狀和柑橘狀態=成熟

現在我嵌套了foreach循環來檢查

 foreach (Citrus fruit in grapefruit)
 {
    foreach (Citrus fruitToo in tangerines)
    {
       PackingContainer container = new PackingContainer();
       if (fruit.Color == fruitToo.Color && 
           fruit.Flavor == fruitToo.Flavor && 
           fruit.Texture == fruitToo.Texture && 
           fruit.State == fruitToo.State)
           { 
              Tangelo tangy = new Tangelo(fruit.Color, fruit.Flavor, fruit.Texture, fruit.State, "A tangelo", new Decimal(0.75);
              container.Add(tangy);
           }
     }
  }

但我敢肯定,有更好的方法可以做到這一點。 我本質上想做一個完整的外部連接(將所有葡萄柚和橘子結合在一起,但使橘子不在交點內)。 我的最終目標是要擁有一個包含一些葡萄柚,一些橘子和一些橘子的PackingContainer。 我敢肯定,LINQ中有一種更優雅的方法可以做到這一點。

...但是我無法從http://msdn.microsoft.com/en-us/library/bb907099.aspxhttp://msdn.microsoft.com/en-us/library/bb384063中弄清楚。 aspx ,它不完全是聯盟,因為我正在修改相交的成員(http://msdn.microsoft.com/zh-cn/library/bb341731.aspx)

沒有什么幫助?

實際上,聽起來您需要一個內部聯接,而不是一個外部聯接。 嵌套的for循環實際上執行的是內部聯接。 好歹:

grapefruit
 .Join(
  tangerines,
  x => new { Color = x.Color, Flavor = x.Flavor, Texture = x.Texture, State = x.State },
  x => new { Color = x.Color, Flavor = x.Flavor, Texture = x.Texture, State = x.State },
  (o,i) => new Tangelo(o.Color, o.Flavor, o.Texture, o.State, "A tangelo", new Decimal(0.75))
 ).Map(x => container.Add(x));

其中“地圖”是IEnumerables的“ ForEach”式擴展方法:

public static void Map<T>(this IEnumerable<T> source, Action<T> func)
{
    foreach (T i in source)
        func(i);
}

編輯:足夠公平。 從這個問題看來,您似乎只對橘子感興趣。 這是外部聯接版本(未經測試,所以如果有任何問題,請通知我!):

var q =
from fruit in grapefruit.Select(x => new { x.Color, x.Flavor, x.Texture, x.State })
   .Union(tangerines.Select(x => new { x.Color, x.Flavor, x.Texture, x.State }))
join g in grapefruit on fruit equals new { g.Color, g.Flavor, g.Texture, g.State } into jg
from g in jg.DefaultIfEmpty()
join t in tangerines on fruit equals new { t.Color, t.Flavor, t.Texture, t.State } into jt
from t in jt.DefaultIfEmpty()
select  (g == null ? 
   t as Citrus : 
   (t == null ? 
    g as Citrus : 
    new Tangelo(g.Color, g.Flavor, g.Texture, g.State, "A tangelo", new Decimal(0.75)) as Citrus
   )
  );

然后可以使用David B的答案中的map方法或AddRange方法將它們添加到容器中。

您不希望為此而加入一個完整的外部連接,或者您會結出一些沒有葡萄柚的橘子和一些沒有橘子的橘子。

這是一個內部聯接。

List<Tangelo> tangelos = (
from fruit in grapefruit
join fruitToo in tangerines
  on new {fruit.Flavor, fruit.Color, fruit.Flavor, fruit.State}
  equals new {fruitToo.Flavor, fruitToo.Color, fruitToo.Flavor, fruitToo.State}
select new Tangelo(fruit.Color, fruit.Flavor, fruit.Texture, fruit.State,
  "A tangelo", new Decimal(0.75))
).ToList()

即使那樣也令人懷疑。 如果3個葡萄柚與1個橘子匹配,那么您會得到3個橘子!

嘗試進行以下過濾,以使每個橘子只得到一個橘子:

List<Tangelo> tangelos = (
from fruit in tangerines
where grapefruit.Any(fruitToo => 
  new {fruit.Flavor, fruit.Color, fruit.Flavor, fruit.State}
  == new {fruitToo.Flavor, fruitToo.Color, fruitToo.Flavor, fruitToo.State})
select new Tangelo(fruit.Color, fruit.Flavor, fruit.Texture, fruit.State,
  "A tangelo", new Decimal(0.75))
).ToList()

當然,一旦有了“橘子清單”,就可以將它們打包

container.AddRange(tangelos);

我認為這可以解決問題:

var cs = from c in citrusList
         group c by new { c.Color, c.Flavor, c.Texture, c.State } into gcs
         let gs = gcs.Where(gc => gc.IsSmall == false)
         let ts = gcs.Where(gc => gc.IsSmall == true)
         let Tangelos = gs
            .Zip(ts, (g, t) =>
                new Tangelo(g.Color, g.Flavor, g.Texture, g.State,
                    "A tangelo", new Decimal(0.75)))
         select new
         {
             gcs.Key,
             Grapefruit = gs.Skip(Tangelos.Count()),
             Tangerines = ts.Skip(Tangelos.Count()),
             Tangelos,
         };

var container = new PackingContainer();

container.AddRange(from c in cs
                   from f in c.Grapefruit
                       .Concat(c.Tangerines)
                       .Concat(c.Tangelos.Cast<Citrus>())
                   select f);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM