1

Assume I have a Category which could have unlimited children and each child could also have unlimited children too.

Just curious, is there a way to retrieve all family of Root node using LINQ?

Mxyk
  • 10,678
  • 16
  • 57
  • 76
nonintanon
  • 213
  • 1
  • 3
  • 9
  • 3
    It sounds like you're asking if you can do recursion with linq? I would suggest looking at this http://stackoverflow.com/questions/4814242/linq-recursion-function – Nathan Aug 08 '12 at 16:06
  • 1
    possible duplicate of [How to flatten tree via LINQ?](http://stackoverflow.com/questions/11830174/how-to-flatten-tree-via-linq) – L.B Aug 08 '12 at 16:12
  • oh, thanks. i'll check those links. – nonintanon Aug 08 '12 at 16:17

2 Answers2

2

There are two common ways to process a recursive structure in C# - by using yield return and by writing a recursive function. I prefer the second way, here is an example:

public static class TreeUtils {
    public static IEnumerable<T> GetAllNodes<T>(
        this T node
    ,   Func<T,IEnumerable<T>> f) 
    {
        return GetAllNodes(new[] {node}, f);
    }
    public static IEnumerable<T> GetAllNodes<T>(
        this IEnumerable<T> e
    ,   Func<T,IEnumerable<T>> f) 
    {
        return e.SelectMany(c => f(c).GetAllNodes(f)).Concat(e);
    }
}

You can use this utility class as follows:

class TreeNode<T> {
    public T Content {get; set;}
    public IEnumerable<TreeNode<T>> Dependents {get;set;}
}

foreach (TreeNode node in TreeUtils.GetAllNodes(root, n => n.Dependents)) {
    Console.WriteLine(node.Content);
}

A somewhat cheating way would be to employ a "recursive" lambda:

using System;
using System.Collections.Generic;

public class Program {
    class Node {
        public int Data;
        public IEnumerable<Node> Dependents { get; set; }
    }
    public static void Main() {
        var root = Create(
            10
        ,   Create(5, Create(3), Create(7, Create(6), Create(8)))
        ,   Create(20, Create(15), Create(30, Create(28), Create(40)))
        );
        // We cannot combine the declaration and definition here
        Func<Node,IEnumerable<Node>> all = null;
        // The recursive magic is in the following line
        all = n => n.Dependents.SelectMany(d => all(d)).Concat(new[] {n});
        // Here is how you can use it
        foreach (var node in all(root)) {
            Console.WriteLine(node.Data);
        }
    }
    // Helper function for creating tree nodes
    private static Node Create(int data, params Node[] nodes) {
        return new Node { Data = data, Dependents = nodes };
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

Lambdas, upon which linq is very dependent, don't support the recursion needed to do such a thing in an intuitive manner; however, using let and the y-combinator you can so it in a non-intuitive manner. Here is a complicated example:

http://blogs.msdn.com/b/lukeh/archive/2007/10/01/taking-linq-to-objects-to-extremes-a-fully-linqified-raytracer.aspx

Hopefully somebody will come up with a more concise one. If so, pick them.

FastAl
  • 6,194
  • 2
  • 36
  • 60