2010-11-04 101 views
0

我有两个列表LINQ合并两个列表(在组合键全外连接)

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

我希望把我所有的柑橘在PackingContainer,但我想先tangelos--的组合葡萄柚和橘子 - 从我的葡萄柚和橘子,其中Citrus.Color =橙色,Citrus.flavor =非常浓郁,Citrus.Texture =粒状和柑橘。状态=成熟

现在我嵌套了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)

帮助不大?

+0

嗯。听起来很好吃。 – dotariel 2010-11-04 18:31:21

回答

0

它实际上听起来像你需要一个内部连接,而不是外部连接。你嵌套的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 
    ) 
); 

然后你就可以使用地图方法或从大卫的AddRange方法将它们添加到容器B的回答。

+0

内部连接只会返回可以制作成橘柚的葡萄柚和橘子。 (HTTP://en.wikipedia。org/wiki/Full_outer_join#Inner_join)我想要所有的葡萄柚和所有的橘子,但我希望符合指定标准的所有葡萄柚和橘子都能变成橘柚。这在我看来就像一个完整的外连接(http://en.wikipedia.org/wiki/Full_outer_join#Full_outer_join) – 2010-11-04 19:21:05

+0

啊,我明白了。答案已被编辑。 – diceguyd30 2010-11-04 21:13:31

+0

看起来像一个体面的答案,虽然在复杂的水平,我认为我最好坚持与foreach循环。看起来这对于LINQ来说并不是一个简单的例子。 – 2010-12-16 19:42:54

0

你不想要一个完整的外连接,否则你会在没有葡萄柚和一些没有蜜桔的橘柚的情况下制作一些橘柚。

这是一个内部连接。

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橘柚果!

试试这个过滤,让每橘子只有一个橘柚:由

container.AddRange(tangelos); 
+0

我想要葡萄柚没有橘柚,橘子没有橘柚,但是葡萄柚需要一些葡萄柚和一些橘子。 1:M的好点虽然匹配,但我希望葡萄柚和橘子之间的1:1映射成为橘柚。 – 2010-11-04 19:28:53

0

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() 

当然,一旦你有橘柚的列表,你可以收拾他们,我觉得这样做的绝招:

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); 
+0

功能?大概。但非常混乱。并不完全是我在寻找的“LINQ中更优雅的方式”。 Zip看起来像一个扩展函数,并具有多个让人和好奇......我会好奇看到性能比较基本嵌套的foreach循环。 – 2010-12-16 19:27:37