4

这是我的产品模型

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

2 回答 2

4

拼凑一个“扁平化这棵树”的类似 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();
于 2012-10-18T15:00:23.783 回答
0

你需要这样的东西:

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 
    });
于 2012-10-18T19:13:14.013 回答