Mark
Mark

Reputation: 3271

Counting parent objects using Linq

I'm fairly new to using linq expressions and trying to refactor some old code. Is there a way to turn the following method into a short and clean Linq expression?

public int GetParentCount(object o)
{ 
    int count = 0;
    object parent = GetParentObject(o);
    while (parent != null)
    {
        count++;
        parent = GetParentObject(parent);
    }
    return count;
}

I've tried searching but got no satisfying results

Upvotes: 4

Views: 797

Answers (3)

bradlis7
bradlis7

Reputation: 3489

Here's a generic function that can work on any type of object, with any object name containing the parent (uses Func<T,T>):

public static class MyExtensions {

  /// <summary>Gets an enumerable of all ancestors.</summary>
  public static IEnumerable<T> Ancestors<T>(this T obj, Func<T, T> expr) where T : class {
    obj = expr.Invoke(obj);
    while(obj != null) {
      yield return obj;
      obj = expr.Invoke(obj);
  }
}

Here's an example application that uses the function:

class MyClass {
    public MyClass Parent { get; set; }
}

void Main()
{
    MyClass a = new MyClass();
    a.Parent = new MyClass();
    a.Parent.Parent = new MyClass();

    a.Ancestors(myObj => myObj.Parent).Count(); // Result: 2
}

Upvotes: 0

Matthew Watson
Matthew Watson

Reputation: 109567

And as an alternative to Ander's solution, a non-recursive approach:

using System;
using System.Linq;
using System.Collections.Generic;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            var obj = new object();
            int count = AllParents(obj).Count(); // Using Linq only here.
            Console.WriteLine(count);
        }

        public static IEnumerable<object> AllParents(object obj)
        {
            while (true)
            {
                obj = GetParentObject(obj);

                if (obj == null)
                    yield break;

                yield return obj;
            }
        }

        // This is merely a hacky test implementation.
        public static object GetParentObject(object obj)
        {
            if (--count == 0)
                return null;

            return obj;
        }

        private static int count = 10;
    }
}

Upvotes: 1

Anders Forsgren
Anders Forsgren

Reputation: 11101

You can enumerate the ancestors like so:

public IEnumerable<MyClass> AncestorsOf(MyClass obj)
{
   var parent = GetParentObject(obj);
   if (parent != null)
   { 
       yield return parent;
       foreach(var grandparent in AncestorsOf(parent))
          yield return grandparent;
   }
}

Getting the total count would then be a simple AncestorsOf(obj).Count()

Upvotes: 2

Related Questions