通过交叉另一个列表来过滤嵌套集合

时间:2017-09-25 21:00:18

标签: c# linq

假设我有以下课程。

class Foo
{
    public int Id { get; set; }
    public List<Foo> Children { get; set; }
}

以及以下ID数组

int[] ids = new int[] { 1, 3, 5 };

以及以下两个对象

var myParentChildrenMatchesFoo = new Foo
{
    Id = 1,
    Children = new List<Foo>
    {
        new Foo {
            Id = 3,
            Children = null
        },
        new Foo {
            Id = 2,
            Children = null
        },
        new Foo {
            Id = 5,
            Children = null
        }
    }
};

var myParentNoMatchesFoo = new Foo
{
    Id = 2,
    Children = new List<Foo>
    {
        new Foo {
            Id = 3,
            Children = null
        },
        new Foo {
            Id = 2,
            Children = null
        },
        new Foo {
            Id = 5,
            Children = null
        }
    }
};

var myChildrenNoMatchesFoo = new Foo
{
    Id = 1,
    Children = new List<Foo>
    {
        new Foo {
            Id = 2,
            Children = null
        },
        new Foo {
            Id = 4,
            Children = null
        },
        new Foo {
            Id = 6,
            Children = null
        }
    }
};
var myNoMatchesFoo = new Foo
{
    Id = 1,
    Children = new List<Foo>
    {
        new Foo {
            Id = 2,
            Children = null
        },
        new Foo {
            Id = 4,
            Children = null
        },
        new Foo {
            Id = 6,
            Children = null
        }
    }
};

如果子节点匹配但子节点不匹配且仅返回匹配的子节点,如何根据我的ids数组的交集返回匹配记录?

预期结果:

myParentChildrenMatchesFoo { Id: 1, Children: [{ Id: 3, Children: []}, { Id: 5, Children: []}] }

myParentNoMatchesFoo { Id: 1, Children: [{ Id: 3, Children: []}, { Id: 5, Children: []}] }

myChildrenNoMatchesFoo { Id: 1, Children: [] }

myNoMatchesFoo { }

这是我目前的方向。我将所有内容添加到列表中,以便我可以使用Linq。

List<Foo> myFoo = new List<Foo>();
myFoo.Add(myChildrenNoMatchesFoo);
myFoo.Add(myNoMatchesFoo);
myFoo.Add(myParentChildrenMatchesFoo);
myFoo.Add(myParentNoMatchesFoo);

我正在使用.SelectMany的重载来搜索子项并展平对象。

var test = myFoo
   .SelectMany(c => c.Children, (parent, child) => new { parent = parent, child = child }).Where(c => ids.Contains(c.child.Id))
   .Select(p => new Foo()
            {
                Id = p.parent.Id,
                Children = new List<Foo>() { p.child }
            })
   .ToList();

然后我可以.GroupBy将父ID重新组合在一起,但似乎应该有更好的方法。我知道我可以很容易地在两个嵌套循环中构建一个新对象,或者我可以创建一个帮助扩展,它可以做我想要的但是我试图找到一个只有Linq的方法,如果没有其他原因而不是看到如果可以的话。

1 个答案:

答案 0 :(得分:0)

显然下面的代码有效。它令人难以置信的丑陋和难以理解。我会向后工作,看看我是否可以清理它或简化它。

var wow = myFoo
        .SelectMany(c => c.Children, (parent, child) => new { parent = parent, child = child })
        .Where(p => ids.Contains(p.parent.Id) || ids.Contains(p.child.Id))
        .Select(p => new
        {
            Id = p.parent.Id,
            Children = p.child
        })
        .GroupBy(g => g.Id, (key, group) => new { Id = key, group = group.Select(g => g.Children) })
        .Select(g => new
        {
            Id = g.Id,
            Children = g.group.Where(c => ids.Contains(c.Id)).ToList()
        }).ToList();