Asked  7 Months ago    Answers:  5   Viewed   62 times

So I have simple tree:

class MyNode
{
 public MyNode Parent;
 public IEnumerable<MyNode> Elements;
 int group = 1;
}

I have a IEnumerable<MyNode>. I want to get a list of all MyNode (including inner node objects (Elements)) as one flat list Where group == 1. How to do such thing via LINQ?

 Answers

50

You can flatten a tree like this:

IEnumerable<MyNode> Flatten(IEnumerable<MyNode> e) =>
    e.SelectMany(c => Flatten(c.Elements)).Concat(new[] { e });

You can then filter by group using Where(...).

To earn some "points for style", convert Flatten to an extension function in a static class.

public static IEnumerable<MyNode> Flatten(this IEnumerable<MyNode> e) =>
    e.SelectMany(c => c.Elements.Flatten()).Concat(e);

To earn more points for "even better style", convert Flatten to a generic extension method that takes a tree and a function that produces descendants from a node:

public static IEnumerable<T> Flatten<T>(
    this IEnumerable<T> e
,   Func<T,IEnumerable<T>> f
) => e.SelectMany(c => f(c).Flatten(f)).Concat(e);

Call this function like this:

IEnumerable<MyNode> tree = ....
var res = tree.Flatten(node => node.Elements);

If you would prefer flattening in pre-order rather than in post-order, switch around the sides of the Concat(...).

Tuesday, June 1, 2021
 
alez
answered 7 Months ago
49

Fixed the issue by making small changes in Xml2TreeNode() function

private void Xml2TreeNode(XElement xNode, TreeNode treeNode)
{
    if (xNode.HasElements) //if node has children
    {
        TreeNode tNode = null;
        int i = 0;
        foreach (XElement subNode in xNode.Elements())
        {
            if (subNode.Descendants().Count() > 0)
            {//handle non-leaf node
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim());
                tn.Nodes.Add(new TreeNode(subNode.FirstNode.ToString().Trim()));
                tn.Tag = treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrived in SaveNodes function
                tNode = tn; //add child nodes
            }
            else
            {//handle leaf node
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim()); //show name of a leaf node element
                tn.Nodes.Add(new TreeNode(subNode.Value.ToString().Trim())); //show value of above element as a child of its name
                tn.Tag = treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrived in SaveNodes function
                tNode = treeNode.Nodes[i++]; //add sibling node
            }

            Xml2TreeNode(subNode, tNode); //recursively add child nodes
        }
    }
}  



private void Xml2TreeNode(XElement xNode, TreeNode treeNode)
{
    if (xNode.HasElements) //if node has children
    {
        TreeNode tNode = null;
        int i = 0;
        foreach (XElement subNode in xNode.Elements())
        {
            if (subNode.Descendants().Count() > 0)
            {//handle non-leaf node
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim());
                ////tn.Nodes.Add(new TreeNode(subNode.FirstNode.ToString().Trim())); //adds extra element-value to node
                tn.Tag = treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrived in TreeNode2Xml function
                tNode = tn; //add child nodes
            }
            else
            {//handle leaf node
                TreeNode tn = treeNode.Nodes.Add(subNode.Name.ToString().Trim()); //show name of a leaf node element
                tn.Nodes.Add(new TreeNode(subNode.Value.ToString().Trim())); //show value of above element as a child of its name
                tn.Tag = treeNode.Nodes[i].Tag = subNode.Attributes().ToList(); //---->these values are retrived in TreeNode2Xml function
                tNode = treeNode.Nodes[i++]; //add sibling node
            }

            Xml2TreeNode(subNode, tNode); //recursively add child nodes
        }
    }
}
Thursday, August 5, 2021
 
DCD
answered 4 Months ago
DCD
39

this is the part that's failing - grp.Select(g => g.OrderId).ToList() - you can't have a .ToList() in the select clause. remove that and you should be fine.

Tuesday, August 17, 2021
 
maniclorn
answered 4 Months ago
19

You can use SelectMany extension method:

var result= foods.SelectMany(f=>f.Value.Select(s=>new Tuple<string, string>(f.Key, s)))
                 .ToList();
Monday, August 23, 2021
 
kiruwka
answered 4 Months ago
45

Essentially, you want to generate a cartesian product and then concatenate the elements of each 2-tuple. This is easiest to do in query-syntax:

var cartesianConcat = from a in seq1
                      from b in seq2
                      select a + b;
Wednesday, September 8, 2021
 
Alix
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share