Searching a Tree Using Linq

Searching a tree using LINQ

It's a misconception that this requires recursion. It will require a stack or a queue and the easiest way is to implement it using recursion. For sake of completeness I'll provide a non-recursive answer.

static IEnumerable<Node> Descendants(this Node root)
{
var nodes = new Stack<Node>(new[] {root});
while (nodes.Any())
{
Node node = nodes.Pop();
yield return node;
foreach (var n in node.Children) nodes.Push(n);
}
}

Use this expression for example to use it:

root.Descendants().Where(node => node.Key == SomeSpecialKey)

Linq recursive search nodes

Another linq recursive solution:

public static IEnumerable<Node> GetAllNodes( Node root )
{
if( root == null )
{
yield break;
}

yield return root;

if ( root.Nodes == null )
{
yield break;
}

foreach ( Node descendant in root.Nodes.SelectMany( GetAllNodes ) )
{
yield return descendant;
}
}

Use like this:

Items.SelectMany( GetAllNodes )

Retrieving a tree structure from a database using LINQ

I'd add a field to the entity to include the parent ID, then I'd pull the whole table into memory leaving the List subs null. Id then iterate through the objects and populate the list using linq to objects. Only one DB query so should be reasonable.

Query a binary tree

The problem you seem to have is that you criteria is impossible.

Take this line: MC.Where(x => ((ID)x).DealNo == 2 && ((ID)x).Strategy == "Fly" && ((Greek)x).GreekType == "Delta" && ((DataPoint)x).DpNo == 14). It is kind of saying that you expect each member of MC to be of type ID, Greek, and DataPoint all at the same time.

Based on your comments it sounds like you need this:

var query =
from id in MC.OfType<ID>()
from greek in id.Children.OfType<Greek>()
from dp in greek.Children.OfType<DataPoint>()
group dp.Value by new
{
id.DealNo,
id.Strategy,
greek.LegOrPos,
greek.GreekType,
dp.DpNo
} into gs
select new
{
gs.Key,
Value = gs.Sum(),
};

When I run that on your data I get this:

query

How to search Hierarchical Data with Linq

That's an extension to It'sNotALie.s answer.

public static class Linq
{
public static IEnumerable<T> Flatten<T>(this T source, Func<T, IEnumerable<T>> selector)
{
return selector(source).SelectMany(c => Flatten(c, selector))
.Concat(new[] { source });
}
}

Sample test usage:

var result = familyRoot.Flatten(x => x.Children).FirstOrDefault(x => x.Name == "FamilyD");

Returns familyD object.

You can make it work on IEnumerable<T> source too:

public static IEnumerable<T> Flatten<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
{
return source.SelectMany(x => Flatten(x, selector))
.Concat(source);
}


Related Topics



Leave a reply



Submit