[英]Creating a tree with LINQ expression
我有一个由存储过程返回的以下字段的C#列表:
CarrierId ParentCarrierId Name Descrition
1 NULL A AA
2 1 B BB
3 1 C CC
4 3 D DD
5 NULL E EE
我需要从这个输出中构造一个嵌套对象列表
所以Carrier的每个对象都应该包含所有孩子的列表。 任何人都可以帮我构建一个LINQ代码来实现这一目标吗?
期望的结果:
CarrierId = 1
|__________________ CarrierId = 2
|__________________ CarrierId = 3
|___________________ CarrierId = 4
CarrierId = 5
期望的结果应如上所述
首先创建一个将父ID映射到其子项的查找:
var lookup = carriers.ToLookup(carrier => carrier.ParentCarrierId);
遍历每个节点并根据查找分配其子节点:
foreach(var carrier in carriers)
carrier.Children = lookup[carrier.CarrierId];
要获取所有根节点,只需从查找中获取空值:
var roots = lookup[null];
注意,整个操作是O(n),因为构建查找是O(n),并且每个单载波的所有子节点都可以在O(n)时间内找到,而不是将O(n ^ 2)时间视为在发布的其他解决方案中(因为他们使用O(n)操作来查找单个节点的所有子节点)。 这使得此代码比其他选项快得多,而且更简单,更短。
你原来的问题有点不同。 我认为每个运营商都应该列出所有后代的清单。 现在看来你只想抱着所有直接的孩子。 这很简单:
c.Children = carrierList.Where(child => child.ParentCarrierId == c.CarrierId).ToList();
如果你想要它作为LINQ查询,那么你必须创建Carrier
新实例:
List<Carrier> rootCarriers = carrierList
.Select(c => new Carrier {
CarrierId = c.CarrierId,
Name = c.Name,
Descrition = c.Descrition,
ParentCarrierId = c.ParentCarrierId,
Children = carrierList
.Where(child => child.ParentCarrierId == c.CarrierId)
.ToList()
})
.Where(c => !c.ParentCarrierId.HasValue)
.ToList();
该查询还根据需要删除所有不是根载波(具有父节点)。
以下显示了两种不同属性Children
和Descendants
,后者甚至返回孙子等等。
public class Carrier
{
public List<Carrier> Descendants { get; set; }
public List<Carrier> Children { get; set; }
public static IEnumerable<Carrier> TraverseDescendants(IEnumerable<Carrier> allCarriers, Carrier rootCarrier)
{
Queue<Carrier> queue = new Queue<Carrier>();
var children = allCarriers.Where(c => c.ParentCarrierId == rootCarrier.CarrierId);
foreach (Carrier c in children)
queue.Enqueue(c);
while (queue.Count > 0)
{
Carrier child = queue.Dequeue();
yield return child;
var grandchildren = allCarriers.Where(c => c.ParentCarrierId == child.CarrierId);
foreach (Carrier c in grandchildren)
queue.Enqueue(c);
}
}
}
使用TraverseDescendents
您可以初始化班级中的List<Carrier> Descendents
。 Children
-list是一个简单的LINQ查询:
foreach (Carrier c in carrierList)
{
c.Descendants = Carrier.TraverseDescendants(carrierList, c).ToList();
c.Children = carrierList.Where(child => child.ParentCarrierId == c.CarrierId).ToList();
}
如果你添加一个public List<Carrier> Children { get; set; }
这将对内存中的可承运的运营商起作用public List<Carrier> Children { get; set; }
public List<Carrier> Children { get; set; }
public List<Carrier> Children { get; set; }
属性到你的Carrier级。
public static class CarrierExt
{
public static List<Carrier> AsTree(this IEnumerable<Carrier> carriers)
{
return carriers.AsTree(null);
}
private static List<Carrier> AsTree(this IEnumerable<Carrier> carriers, int? parentId)
{
return (from carrier in carriers
where carrier.ParentCarrierId == parentId
let children = carrier.Children = carriers.AsTree(carrier.CarrierId)
select carrier).ToList();
}
}
编辑:请注意,这会将顶级列表减少到只有2个根元素。
试试这个
class Program
{
static void Main(string[] args)
{
IList<Carrier> CarrierList = new List<Carrier>();
CarrierList.Add(new Carrier { CarrierId = 1, Name = "A", Description = "AA", ParentCarrierId = null });
CarrierList.Add(new Carrier { CarrierId = 2, Name = "B", Description = "BB", ParentCarrierId = 1 });
CarrierList.Add(new Carrier { CarrierId = 3, Name = "C", Description = "CC", ParentCarrierId = 1 });
CarrierList.Add(new Carrier { CarrierId = 4, Name = "D", Description = "DD", ParentCarrierId = 3 });
CarrierList.Add(new Carrier { CarrierId = 5, Name = "E", Description = "EE", ParentCarrierId = null });
Temp temp = new Temp();
IList<Carrier> CarrierList1=new List<Carrier>();
foreach (Carrier carrier in CarrierList.Where(p => p.ParentCarrierId == null).ToList() )
{
CarrierList1.Add(temp.Recursive(carrier, CarrierList));
}
}
}
public class Temp
{
public Carrier Recursive(Carrier carrier,IList<Carrier> carrierList)
{
if (carrierList.Where(c => c.ParentCarrierId == carrier.CarrierId).Count() <1)
{
return carrier ;
}
else
{
IList<Carrier> newList = new List<Carrier>();
foreach (Carrier ca in carrierList.Where(c => c.ParentCarrierId == carrier.CarrierId)){
newList.Add(Recursive(ca, carrierList));
}
carrier.CarrierList = newList;
return carrier;
}
}
}
public class Carrier
{
public int CarrierId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int? ParentCarrierId { get; set; }
public IList<Carrier> CarrierList { get; set; }
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.