如何为嵌套集合编写Linq或Lambda表达式

时间:2021-03-11 19:06:20

I know simple linq, but here the problem statement has multiple level of nesting. How to write Linq or Lambda expression for nested collections.

我知道简单的linq,但这里的问题陈述有多层次的嵌套。如何为嵌套集合编写Linq或Lambda表达式。

Input Object Definition:

输入对象定义:

public class Service
{
    public string Name { get; set; }
    public List<Service> ChildServices{ get; set; }

    public List<Action> AvailableActions{ get; set; }
}

public class Action
{
    public string Name { get; set; }
    public List<string> Parameters{ get; set; }

    public void Execute()
    {
        ...
    }
}

The nesting can go to multiple levels

嵌套可以达到多个级别

Linq Expected Output

Linq预期产出

here I need to write Linq or Lambda expression which

在这里我需要编写Linq或Lambda表达式

  1. Gets all the Services
  2. 获取所有服务

  3. Get service with a given name
  4. 获取具有给定名称的服务

2 个解决方案

#1


If we can assume that you start with a list of services, like this:

如果我们可以假设您从服务列表开始,如下所示:

var services = new List<Service>()
{
    new Service()
    {
        Name = "A",
        ChildServices = new List<Service>()
        {
            new Service() { Name = "C", ChildServices = new List<Service>() },
            new Service()
            {
                Name = "D",
                ChildServices = new List<Service>()
                {
                    new Service() { Name = "E", ChildServices = new List<Service>() },
                    new Service() { Name = "F", ChildServices = new List<Service>() },
                }
            },
        }
    },
    new Service()
    {
        Name = "B",
        ChildServices = new List<Service>()
        {
            new Service() { Name = "G", ChildServices = new List<Service>() },
            new Service() { Name = "H", ChildServices = new List<Service>() },
        }
    },
};

Which looks like this:

看起来像这样:

如何为嵌套集合编写Linq或Lambda表达式

Then this query will flatten the list out:

然后,此查询将展开列表:

Func<IEnumerable<Service>, IEnumerable<Service>> traverse = null;
traverse = ss =>
    from s in ss
    from s2 in new [] { s }.Concat(traverse(s.ChildServices))
    select s2;

Calling traverse(services) returns this:

调用遍历(服务)返回:

如何为嵌套集合编写Linq或Lambda表达式

You can then look-up a service by name using a normal LINQ query or you could make a dictionary like this:

然后,您可以使用普通的LINQ查询按名称查找服务,或者您可以创建如下字典:

var serviceByName = traverse(services).ToDictionary(x => x.Name);

var serviceG = serviceByName["G"];

#2


I don't think there is direct way to recursively query nested collection (Atleast I'm aware).

我不认为有直接的方式来递归查询嵌套集合(我知道Atleast)。

Below solution might work for your cases.

以下解决方案可能适合您的情况。

public class Service
{
    public string Name { get; set; }
    public List<Service> ChildServices{ get; set; }

    public List<Action> AvailableActions{ get; set; }
}

public class Action
{
    public string Name { get; set; }
    public List<string> Parameters{ get; set; }

    public void Execute()
    {

    }
}

public static class Extensions
{
    public static IEnumerable<Service> GetAllServices(this Service node)
    {
        yield return node;
        if(node.ChildServices != null)
        {
            foreach(var child in node.ChildServices)
            {
                foreach(var childOrDescendant in child.GetAllServices())
                {
                    yield return childOrDescendant;
                }
            }
        }
    }
}

Working fiddler Sample

工作小提琴样品

#1


If we can assume that you start with a list of services, like this:

如果我们可以假设您从服务列表开始,如下所示:

var services = new List<Service>()
{
    new Service()
    {
        Name = "A",
        ChildServices = new List<Service>()
        {
            new Service() { Name = "C", ChildServices = new List<Service>() },
            new Service()
            {
                Name = "D",
                ChildServices = new List<Service>()
                {
                    new Service() { Name = "E", ChildServices = new List<Service>() },
                    new Service() { Name = "F", ChildServices = new List<Service>() },
                }
            },
        }
    },
    new Service()
    {
        Name = "B",
        ChildServices = new List<Service>()
        {
            new Service() { Name = "G", ChildServices = new List<Service>() },
            new Service() { Name = "H", ChildServices = new List<Service>() },
        }
    },
};

Which looks like this:

看起来像这样:

如何为嵌套集合编写Linq或Lambda表达式

Then this query will flatten the list out:

然后,此查询将展开列表:

Func<IEnumerable<Service>, IEnumerable<Service>> traverse = null;
traverse = ss =>
    from s in ss
    from s2 in new [] { s }.Concat(traverse(s.ChildServices))
    select s2;

Calling traverse(services) returns this:

调用遍历(服务)返回:

如何为嵌套集合编写Linq或Lambda表达式

You can then look-up a service by name using a normal LINQ query or you could make a dictionary like this:

然后,您可以使用普通的LINQ查询按名称查找服务,或者您可以创建如下字典:

var serviceByName = traverse(services).ToDictionary(x => x.Name);

var serviceG = serviceByName["G"];

#2


I don't think there is direct way to recursively query nested collection (Atleast I'm aware).

我不认为有直接的方式来递归查询嵌套集合(我知道Atleast)。

Below solution might work for your cases.

以下解决方案可能适合您的情况。

public class Service
{
    public string Name { get; set; }
    public List<Service> ChildServices{ get; set; }

    public List<Action> AvailableActions{ get; set; }
}

public class Action
{
    public string Name { get; set; }
    public List<string> Parameters{ get; set; }

    public void Execute()
    {

    }
}

public static class Extensions
{
    public static IEnumerable<Service> GetAllServices(this Service node)
    {
        yield return node;
        if(node.ChildServices != null)
        {
            foreach(var child in node.ChildServices)
            {
                foreach(var childOrDescendant in child.GetAllServices())
                {
                    yield return childOrDescendant;
                }
            }
        }
    }
}

Working fiddler Sample

工作小提琴样品