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