使用LINQ查找公共组件

时间:2016-03-16 11:41:15

标签: c# .net linq

我正在尝试查找所有具有共同组件的订单以及共同的组件列表:

组件类:

public class Component
{
    public Component(string name)
    {
        this.Name = name;
    }
    public string Name { get; private set; }
}

订单类:

internal class Order
{
    public Order(string name,List<Component> components)
    {
        this.Name = name;
        this.Components = components;
    }
    public string Name { get; private set; }

    public List<Component>Components { get; private set; }
}

例如:

var component1 = new Component("B1");
var component2 = new Component("B2");
var component3 = new Component("B3");
var component4 = new Component("B4");

var order1 = new Order("M1", new List<Component> { component2 });
var order2 = new Order("M2", new List<Component> { component1, component2, component3, component4 });
var order3 = new Order("M3", new List<Component> { component1, component2 });

var dependents = from cmp1 in order1.Components
                 join cmp2 in order2.Components
                 on cmp1.Name equals cmp2.Name
                 select new
                 {
                     order1Name = order1.Name,
                     order2Name = order2.Name,
                     ComponentName = cmp1.Name
                 };

var result = dependents.ToList();

结果显示正确的信息,order1order2之间的公共组件component2(&#34; B2&#34;)。

如何使用订单列表使其更通用:

    var orders = new List<Order> { order1, order2, order3 };

我想得到结果,对于每2个订单,共同的组件列表而不是为每个可能的对执行。 我认为这就像:

var allDependents = 
runs.ForEach(order=>order.Components)                
....
from cmp1 in order1.Components
join cmp2 in order2.Components
on cmp1.Name equals cmp2.Name
select new
{
    order1Name = order1.Name,
    order2Name = order2.Name,
    ComponentName = cmp1.Name
};

其他信息:

根据下图,我们可以看到每两个订单,一个组件列表

enter image description here

5 个答案:

答案 0 :(得分:4)

假设所有名称都是唯一的,您可以这样做。

var results = from o1 in orders
              from c1 in o1.Components
              from o2 in orders.SkipWhile(o => o.Name != o1.Name)
              from c2 in o2.Components
              where o1.Name != o2.Name && c1.Name == c2.Name
              select new 
              {  
                  Order1 = o1.Name,   
                  Order2 = o2.Name,   
                  Component = c1.Name   
              };

foreach(var r in results) Console.WriteLine(r);

它产生此输出

  

{Order1 = M1,Order2 = M2,Component = B2}

     

{Order1 = M1,Order2 = M3,Component = B2}

     

{Order1 = M2,Order2 = M3,Component = B1}

     

{Order1 = M2,Order2 = M3,Component = B2}

答案 1 :(得分:4)

一种可行的有效方法是使用半连接以及其他标准:

var orders = new List<Order> { order1, order2, order3 };
var orderComponents = from order in orders
         from component in order.Components
         select new { order, component };
var dependents =
    from e1 in orderComponents
    join e2 in orderComponents on e1.component.Name equals e2.component.Name
    where e2.order != e1.order && e2.order.Name.CompareTo(e1.order.Name) > 0
    select new
    {
        order1Name = e1.order.Name,
        order2Name = e2.order.Name,
        ComponentName = e1.component.Name
    };

唯一需要提及的细节是标准e2.order != e1.order && e2.order.Name.CompareTo(e1.order.Name) > 0。第一个条件从左侧排除顺序,而第二个条件排除重复,如{M2,M1}。

答案 2 :(得分:1)

我对Fluent Linq语法更有经验,您可以在其中执行所需操作:

var orders = new[] { order1, order2, order3 };

var dependents = orders.SelectMany(order =>
        orders
        .Where(other => other.Name != order.Name)
        .SelectMany(other => other.Components.Intersect(order.Components)
        .Select(c => new { order, other, component = c }))
    ).ToList();

答案 3 :(得分:1)

您可以使用查找(警告:未经测试的代码):

var lookup = orders
    .SelectMany(ord => ord.Components.Select(cmp => new { Order = ord, Component = cmp)
    .ToLookup(obj => obj.Component /* or obj.Component.Name, if you prefer */)
    .Where(lkp => lkp.Count() > 1);

foreach(var orders in lookup)
{
    // orders.Key is the component, orders is an Enumeration of orders containing that component.
}

答案 4 :(得分:0)

如果您在IEquatable<T>Component上实施Order,并覆盖object.Equals()(作为良好做法),您可以执行以下操作:

var ordersA = new List<Order> { order1, order2, order3 };
var ordersB = new List<Order> { order2, order3 };

bool equal = ordersA.Equals(ordersB);

&#39;等于&#39; Component上的实现还允许您通过使用集合交集来获取通用组件,如:

var compA = new List<Component> { c1, c2, c3};
var compB = new List<Component> { c2, c3};

var commonComponents = compA.Intersect(compB);

您甚至可以在Intersect列表中使用Order