简体   繁体   中英

C# LINQ - Return a typed filtered list based on a child property that is inside another list

Given the Objects :

class Parent
{
    private int id;

    public int Id
    {
        get { return id; }
        set { id = value; }
    }

    private List<Child> childrenList;

    public List<Child> ChildrenList
    {
        get { return childrenList; }
        set { childrenList = value; }
    }
}

class Child
{
    private int idSub;

    public int IdSub
    {
        get { return idSub; }
        set { idSub = value; }
    }

    private bool isST;

    public bool IsST
    {
        get { return isST; }
        set { isST = value; }
    }
}

I have a List<Parent> parentList = new List<Parent>() and inside Parent object there is a list of Child which is called ChildrenList.

Child has a property IsST .

I want to return only the Child which has the property IsST equals true and if the Parent doesn't satisfy the condition, doesn't need to be returned.

And both lists returned, need to be typed with its respectively types.

What I have so far:

List<Parent> parentList = new List<Parent>()
{
    new Parent()
    {
        Id = 1,
        ChildrenList = new List<Child>()
        {
           new Child()
           {
               IdSub = 1,
               IsST = true
           },
           new Child()
           {
               IdSub = 2,
               IsST = true
           }
        }
    },
     new Parent()
    {
        Id = 2,
        ChildrenList = new List<Child>()
        {
           new Child()
           {
               IdSub = 3,
               IsST = false
           },
           new Child()
           {
               IdSub = 4,
               IsST = true
           }
        }
    },
     new Parent()
    {
        Id = 3,
        ChildrenList = new List<Child>()
        {
           new Child()
           {
               IdSub = 5,
               IsST = false
           },
           new Child()
           {
               IdSub = 6,
               IsST = false
           }
        }
    }
};


var parentFilteredList = parentList
            .Select(c => c.ChildrenList
                            .Where(d => d.IsST)
                            .ToList())
            .ToList();

But the list of parents in the parentFilteredList it's not of type List<Parent> .

Result_so_far

I need it to be List<Parent> because the Parent object in the real case there are a lot of properties, as well as the Child . Select new it's not an option.

Any help?

var parentFilteredList = parentList
            .Select(c => c.ChildrenList
                            .Where(d => d.IsST)
                            .ToList())
            .ToList();

In the following statement you are selecting the childrenList.

var parentFilteredList = parentList
        .Where(c => c.ChildrenList.Any(d => d.IsST)).ToList();

If you are looking to return all the parents where at least one child's ST is true -

var parentFilteredList = parentList
     .Where(c => c.ChildrenList.Any(d => d.IsST))
     .ToList();

Or if you want to also filter the children's list inside these parents -

var parentFilteredList = parentList
     .Where(c => c.ChildrenList.Any(d => d.IsST))
     .Select(c => 
         {
             c.ChildrenList = c.ChildrenList.Where(d => d.IsST).ToList();
             return c;
         }).ToList();

Note that this will effect your original parents - I'm not sure that's a desirable outcome.

The basic idea is to use SelectMany , but there are a couple wrinkles depending on assumptions.

Basic code:

var list = parents.SelectMany
(
    p => p.ChildrenList.Where( c => c.IsST )
);

The above assumes there are 0 or 1 children per parent that match. If you want to handle the case where a parent has two or more matching children, you'll need one of the variants below.

If you want to throw an exception if a parent has two or more children that match:

var list = parents.SelectMany
(
    p => p.ChildrenList.Single( c => c.IsST )
);

If you want to exclude parents that have two children that match:

var list = parents.SelectMany
(
    p => p.ChildrenList.SingleOrDefault( c => c.IsST )
    ??   Enumerable.Empty<Child>()
);

If you want to include the first child that matches:

var list = parents.SelectMany
(
    p => p.ChildrenList
          .Where( c => c.IsST )
          .Take(1)
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM