Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用LINQ查找公共组件_C#_.net_Linq - Fatal编程技术网

C# 使用LINQ查找公共组件

C# 使用LINQ查找公共组件,c#,.net,linq,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<Compon

我试图找到所有具有共同组件的订单,以及共同组件列表:

组件类别:

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; }
}
我希望得到的结果是,对于每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
};
其他信息:

如下图所示,我们可以看到每2个订单的组件列表


如果在
组件和
顺序上实现
IEquatable
,并重写
对象.Equals()
(作为良好实践),则可以执行以下操作:

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

bool equal = ordersA.Equals(ordersB);

您甚至可以在
顺序的列表上使用
Intersect

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

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}


我对流畅的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();
您可以使用查找(警告:未测试代码):


一种可能的有效方法是将半联接与以下附加条件一起使用:

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
    };
var orders=新列表{order1,order2,order3};
var orderComponents=来自订单中的订单
按顺序从组件开始。组件
选择新{顺序,组件};
var依赖项=
从e1到orderComponents
在e1.component.Name上的orderComponents中加入e2等于e2.component.Name
哪里有e2.order!=e1.order&&e2.order.Name.CompareTo(e1.order.Name)>0
选择新的
{
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}。

orders.SelectMany(col=>col.Components,(o,co)=>new{o=o.Name,C=co.Name})。GroupBy(key=>key.C)。选择(kv=>new{K=kv.key,L=string.Join(“,”,kv.Select(kvv=>kvv.o)))将生成重复项。基本上,它将匹配M1中的B2作为“顺序”,M2作为“其他”,然后它将匹配它们,其中M1是“其他”,M2是“顺序”。正确。根据查询的大小以及项目是否由字符串标识,很容易添加.Distinct()
Distinct
将不起作用,因为重复项不是完全重复项。基本上一个是,另一个是。很好,如果我需要结果:{Order1=M1,Order2=M2,Component=B2}{Order1=M1,Order2=M3,Component=B2}{Order1=M2,Order2=M3,Component=B1,B2},我需要一个新的LINQ并执行一个group by,对吗?笛卡尔积。O(N^2)。但当然(LINQ标签的典型特征)没人关心。
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);
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();
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.
}
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
    };