Filtrer une liste hiérarchique à l'aide de linq

c# expression-trees linq

Question

Voici mon modèle pour le produit

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

Je dois filtrer la liste ci-dessus contenant le numéro de produit inférieur à 5, c.-à-d. le résultat devrait être une liste de produits dont le numéro de produit est inférieur à 5.

Y a-t-il des extensions disponibles? S'il vous plaît aider.

Voici mon résultat attendu

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

Réponse acceptée

Il est assez facile de créer une fonction similaire à LINQ "aplatir cet arbre"

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

que vous pouvez ensuite utiliser dans LINQ classique, par exemple

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

EDIT : De votre édition, je peux voir que ce n'est pas tout à fait ce que vous vouliez. (Vous ne voulez pas une liste de produits, vous voulez un arbre de produits ...) Je vais laisser ceci ici car je l'aime plutôt comme solution à ce que je pensais que votre problème était, mais j'aurai Pensez aussi à votre nouveau problème ...

EDIT : Si cela ne vous dérange pas de modifier vos objets originaux, vous pouvez utiliser ceci comme suit:

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

Réponse populaire

Vous avez besoin de quelque chose comme ça:

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

que vous appellerez comme ceci:

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



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi