使用Linq选择集合子集

本文关键字:子集 集合 选择 Linq 使用 | 更新日期: 2023-09-27 18:19:19

在本示例中,如何仅获取具有任何活动栏的foo,并仅返回集合中的活动栏?

一个可能的解决方案是这样的,但它需要重新创建Foo元素:

fooList
    .Where(f => f.Bars.Any(b => b.IsActive))
    .Select(f => new Foo()
    {
        Name = f.Name,
        Bars = f.Bars.Where(b => b.IsActive).ToList()
    });
public class Foo
{
    public string Name { get; set; }
    public ICollection<Bar> Bars { get; set; }
}
public class Bar
{
    public string Name { get; set; }
    public bool IsActive { get; set; }
}

编辑1

目标是只获取具有活动Bar 的foo,仅获取活动Bar。

FooA
    Bar1 (Active)
    Bar2 (Inactive)
FooB
    Bar3 (Inactive)
    Bar4 (Inactive)
FooC
    Bar5 (Active)
    Bar6 (Active)

的向往的结果:

FooA
    Bar1 (Active)
FooC
    Bar5 (Active)
    Bar6 (Active)

正如所指出的有许多简单的解决方案,但我想知道Linq是否有任何方法可以做到这一点,而无需检索所有bar,然后在循环中放弃非活动,就像所有bar在内存中检索一样。

使用Linq选择集合子集

你需要使用

向列表中添加数据

List<Foo> employees = new List<Foo>();
Foo employee = new Foo();
employee.Name = "Emp1";
employee.Bars = new List<Bar>();
employee.Bars.Add(new Bar { Name = "Alpesh", IsActive = true });
employee.Bars.Add(new Bar { Name = "Krunal", IsActive = true });
employee.Bars.Add(new Bar { Name = "Karthik", IsActive = false });
employee.Bars.Add(new Bar { Name = "Rakesh", IsActive = true });
employees.Add(employee);

只获取活动数据

List<Foo> newList = employees.Select(m => new Foo
        {
            Name = m.Name,
            Bars = m.Bars.Where(u => u.IsActive == true).ToList()
        }).ToList();
return newList;

如果您不想重新创建Foo's,则使用循环

foreach(var foo in fooList.Where(f => f.Bars.Any(b => b.IsActive)))
{
    foo.Bars = foo.Bars.Where(b => b.IsActive).ToList();
}

如果您想要从所有Foo中提取活动Bar实例的列表,但不需要知道它们来自哪个Foo实例,这应该为您工作:

var activeBars = fooList.SelectMany(f => f.Bars)
                        .Where(b => b.IsActive)
                     // .Distinct() /* eliminate duplicates if you want */
                        .ToList();

SelectMany运算符将每个Foo中的Bars连接成一个序列。Where操作符只过滤掉活动的操作符。ToList()强制立即填充快照

这给您一个List<Bar>,它只包含Bar实例,其中IsActive == true。如果两个或多个Foo可能包含相同的Bar,并且您希望消除这些重复,则在ToList()之前添加Distinct()操作符。

可以在select子句中处理Foo对象。lambda不一定是简单的表达式,它们可以包含多个语句。

var cleanedList = fooList.Where(f => f.Bars.Any(b => b.IsActive))
                         .Select(f => {
                                          f.Bars.RemoveAll(b => !b.IsActive); 
                                          return f;
                                      }
                                 );