使用C# LINQ - 返回一个基于另一个列表内的子属性进行筛选的类型化列表。

3
给定对象:
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; }
    }
}

我有一个 List<Parent> parentList = new List<Parent>(), 其中Parent对象内部有一个名为ChildrenList的Child列表。 Child有一个属性IsST
我希望只返回具有属性IsST等于true的Child,如果Parent不满足条件,则不需要返回。
并且两个列表返回时,需要按其各自类型进行输入。
到目前为止我的代码如下:
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();

但是parentFilteredList中的父母列表不是List<Parent>类型。

Result_so_far

我需要它是List<Parent>,因为在实际情况中,Parent对象有很多属性,以及Child。选择新的不是一个选项。

需要帮助吗?


1
你说的“需要它被键入”,目前parentFilteredList的类型是List<List<Child>>,我猜你想要一个List<Parent>,是吗? - Ousmane D.
1
你想要返回所有至少有一个孩子的ST为真的父母吗?var parentFilteredList = parentList.Where(c => c.ChildrenList.Any(d => d.IsST)).ToList(); 或者你也想过滤这些父母内部的孩子列表吗? - Zohar Peled
1
@ZoharPeled 可能只有我一个人这样认为,但是我越读描述越觉得OP想要的是 parentList .Select(c => new Parent { Id = c.Id, ChildrenList = c.ChildrenList .Where(d => d.IsST) .ToList() }).Where(p => p.ChildrenList.Count >= 1).ToList() - Ousmane D.
@Aominè,你的代码很好用,但是我不想创建一个新的“Parent”,因为在实际情况中,“Parent”有很多属性,这将导致我手动填写所有这些属性。 - bck
@ZoharPeled 我也想在这些父级中过滤子列表。 - bck
3个回答

6
如果你想返回所有至少有一个子节点ST为true的父节点 -
var parentFilteredList = parentList
     .Where(c => c.ChildrenList.Any(d => d.IsST))
     .ToList();

如果您想过滤这些父级内的子列表:

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

请注意,这将影响您原始的父级 - 我不确定这是否是一个理想的结果。

它完美地运行了!只是出于好奇,我该如何不影响原始父级?因为使用这段代码会导致第二个父级的第二个子级丢失。 - bck
1
为了不影响原始对象,您需要在选择中创建新对象。 - Zohar Peled

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

在下面的语句中,您正在选择 childrenList。
var parentFilteredList = parentList
        .Where(c => c.ChildrenList.Any(d => d.IsST)).ToList();

该语句返回具有两个子元素的父元素,其中一个子元素具有属性IsST等于true,另一个子元素具有属性IsST等于false。实际上,我想过滤仅具有属性IsST等于true的子元素。 - bck
你需要使用 All 而不是 Any - Harsh
这种方式只返回其所有子级具有IsST等于true属性的父级,而我想要具有该属性为true的至少一个子级的父级,并同时过滤子级。 - bck

0
基本思路是使用SelectMany,但是根据假设有一些细节需要注意。
基本代码:
var list = parents.SelectMany
(
    p => p.ChildrenList.Where( c => c.IsST )
);

以上假设每个父级只有0或1个匹配的子级。如果您想处理一个父级有两个或更多匹配子级的情况,您需要使用以下其中一种变体。
如果您想在一个父级有两个或更多匹配子级时抛出异常:
var list = parents.SelectMany
(
    p => p.ChildrenList.Single( c => c.IsST )
);

如果您想排除有两个匹配子女的父母:

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

如果您想包含与之匹配的第一个子元素:

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

第一个和最后一个代码片段返回一个List<Child>,我需要返回一个List<Parent>。请查看已接受的答案(@Zohar Peled),它可以按预期工作。 - bck
谢谢Bruno,但我认为问题在于对需求的明确理解,这是许多软件问题共通的地方。 - John Wu
我明白了,抱歉没有表达清楚,感谢您为社区提供帮助。 - bck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接