使用Linq展平嵌套列表,而不是foreach循环

时间:2018-09-05 14:31:53

标签: c# asp.net linq

我有一个定期班-我在下面简化了它。

public class SiloNode
{
    public string Key { get; private set; }
    public string Url { get; private set; }
    public List<SiloNode> Children { get; private set; }
}

尽管从理论上讲,它可以永远嵌套,但是节点将永远只下降两个级别。因此,顶级节点可以有一个孩子,但是一个孩子不能有孩子。

我有一个主列表,其中包含所有顶级节点及其嵌套的子节点。

但是,我需要将所有节点放入一个平面列表中-节点1,其子节点,然后是节点2,等等。

我在这方面的知识有限,但是我可以在主列表上执行诸如foreach之类的操作,并创建一个新列表,如下所示:

public IEnumerable<SiloNode> GetLinks(IEnumerable<SiloNode> masterList)
{
    var newList = new List<SiloNode>();

    foreach (var node in masterList)
    {
        newList.Add(node);
        newList.AddRange(node.Children);
    }

    return newList;
}

但是,我知道可能有更好的方法可用,但是我无法弄清楚如何将foreach转换为Linq语句来执行相同的操作。换句话说,一起选择父级及其子级。

任何帮助表示赞赏。

5 个答案:

答案 0 :(得分:2)

您可以使用SelectMany,只需将单亲父母及其子女联系在一起:

List<SiloNode> newList = masterList.SelectMany(n => new[]{ n }.Concat(n.Children)).ToList();

答案 1 :(得分:2)

masterList已包含父节点,并连接子节点

var nodes = masterList.Concat(masterList.SelectMany(x=> x.Children));

答案 2 :(得分:2)

如果只有两个级别,则应该执行以下操作:

public IEnumerable<SiloNode> GetLinks(IEnumerable<SiloNode> masterList)
{
    return masterList.SelectMany(m => new SiloNode[] { m }.Concat(m.Children));
}

答案 3 :(得分:2)

如果您想保留订单并压平一个以上的孩子水平,我认为类似的事情就可以了。 CheckBox或在循环ToggleButton

中使用
var nodes = GetLinks(masterList);

答案 4 :(得分:0)

我以前看过这个答案,但是找不到问题。这可以满足您的需要,而无需深入节点结构:

public IEnumerable<SiloNode> Flatten(IEnumerable<SiloNode> nodes)
{
    var queue = new Queue<SiloNode>();

    foreach (var node in nodes)
    {
        queue.Enqueue(node);
    }         

    while (queue.Count > 0)
    {
        var node = queue.Dequeue();

        foreach (var child in node.Children)
        {
             queue.Enqueue(child);
        }

        yield return node;
    }
}

编辑:这不会保留您想要的顺序,但是您可以使用堆栈而不是队列。