簡體   English   中英

使用LINQ表達式創建樹

[英]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(); 

該查詢還根據需要刪除所有不是根載波(具有父節點)。

以下顯示了兩種不同屬性ChildrenDescendants ,后者甚至返回孫子等等。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM