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

5未満のProductNumberを含む上記のリストをフィルタリングする必要があります。出力は、製品番号が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 に答える