簡體   English   中英

使用linq過濾分層列表

[英]Filter a hierarchical list using linq

這是我的產品型號

public class Product
{
    public string Name{ get; set; }

    public int ProductNumber{ get; set; }

    public List<Product> ProductList { get; set; }
}

//// below is the structure of the list
IList<Product> rootList = new List<Product>
            {
                new Product 
                { 
                    ProductNumber = 1, Name = "A", 
                    ProductList = new List<Product> { new Product { ProductNumber = 2, Name = "A1", 
                        ProductList = new List<Product> { new Product { ProductNumber = 3, Name = "A2", ProductList = new List<Product>()} }}  
                    }
                },

                new Product 
                { 
                    ProductNumber = 4, Name = "B", 
                    ProductList = new List<Product> { new Product { ProductNumber = 5, Name = "B1", 
                        ProductList = new List<Product> { new Product { ProductNumber = 6, Name = "B2", ProductList = new List<Product>()} }}  
                    }
                },

                 new Product 
                { 
                    ProductNumber = 7, Name = "C", 
                    ProductList = new List<Product> { new Product { ProductNumber = 8, Name = "C1", 
                        ProductList = new List<Product> { new Product { ProductNumber = 9, Name = "C2", ProductList = new List<Product>()} }}  
                    }
                }
            };

我需要過濾上面包含ProductNumber小於5的列表,即。 輸出預計是產品編號小於5的產品列表。

有沒有可用的擴展? 請幫忙。

這是我的預期結果

            Product 
            { 
                ProductNumber : 1, 
                Name : "A", 
                ProductList : { { 
                          ProductNumber : 2, 
                          Name : "A1", 
                          ProductList :{ { 
                                  ProductNumber = 3, 
                                  Name : "A2", 
                                  ProductList : null} }}  
                }
            },

            Product 
            { 
                ProductNumber : 4, 
                Name : "B"
                ProductList : null
            } 

將“扁平 - 這棵樹”類似LINQ的功能拼湊起來相當容易

public static IEnumerable<T> Flatten<T>(
    this IEnumerable<T> source,
    Func<T, IEnumerable<T>> childSelector)
{
    HashSet<T> added = new HashSet<T>();
    Queue<T> queue = new Queue<T>();
    foreach(T t in source)
        if (added.Add(t))
            queue.Enqueue(t);
    while (queue.Count > 0)
    {
        T current = queue.Dequeue();
        yield return current;
        if (current != null)
        {
            IEnumerable<T> children = childSelector(current);
            if (children != null)
                foreach(T t in childSelector(current))
                    if (added.Add(t))
                        queue.Enqueue(t);
        }
    }
}

您可以在常規LINQ中使用它,例如

var lessThanFive = rootList
    .Flatten(p => p.ProductList)
    .Where(p => p.ProductNumber < 5)
    .ToList();

編輯 :從你的編輯我可以看到這不是你想要的。 (你不想要一個產品列表,你想要一個產品樹......)我將把它留在這里,因為我非常喜歡它作為我認為你的問題的解決方案,但我會有想想你的新問題......

編輯 :如果您不介意修改原始對象,可以按如下方式使用:

rootList = rootList.Where(p => p.ProductNumber < 5).ToList();
foreach (var pr in rootList.Flatten(p => p.ProductList))
    pr.ProductList = pr.ProductList.Where(p => p.ProductNumber < 5).ToList();

你需要這樣的東西:

public static class EnumerableExtensions
{
    public static IEnumerable<TR> Recur<T, TR>(
        this IEnumerable<T> source, 
        Func<T, bool> filter, 
        Func<T, IEnumerable<T>> recursor, 
        Func<T, IEnumerable<T>, TR> resultor)
    {
        foreach(var t in source)
            if (filter(t))
                yield return resultor(t, recursor(t));
    }
}

你會這樣稱呼:

var q = rootList.Recur(
    p => p.ProductNumber < 5,
    p => p.ProductList,
    (p, cs) => new 
    {
        p.ProductNumber, 
        p.Name,
        ProductList = cs 
    });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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