2

I want to find all Persons who are left handed using recursive linq via extension method.

I've seen this answer but there is a problem (imho) with the this : (when applied as extension method because of the static context)

keyword this is not valid in static method

So here is what i've tried :

I have a Person class :

public class Person
{
        public  List<Person> Children = new List<Person>();
        public bool IsLeftHanded;
}

And here is the code for the externsion method :

public static class Extensions
{   
        public static IEnumerable<Person> DescendantsAndSelf(this IEnumerable<Person> list)
        {
         yield return this;
        foreach (var item in list.SelectMany(x => x.Children.DescendantsAndSelf()))
        {
            yield return item;
        }
    }
}

But there is a problem with yield return this;

Question :

How can I fix my code in order to support the "me and my childs" trick ? ( goal : find all persons who are left handed)

nb

please notice that I want to use linq and recursion in order to get experienced with linq using recursion.

Community
  • 1
  • 1
Royi Namir
  • 144,742
  • 138
  • 468
  • 792

2 Answers2

3

I'd rather see it working like this:

public static IEnumerable<Person> DescendantsAndSelf(this Person person)
{
    yield return person;
    foreach (var item in person.Children.SelectMany(x => x.DescendantsAndSelf()))
    {
        yield return item;
    }
}

and run it against person not children, like this:

var person = new Person();
... do stuff
var desc = person.DescendantsAndSelf();

Correct me if I see it wrong.

Kamil Budziewski
  • 22,699
  • 14
  • 85
  • 105
  • Dumb question, but is the point of using "yield return" (as opposed to building up a list and returning it) just to get the benefits of deferred execution, or is there another reason? – vargonian Jan 13 '14 at 08:22
  • 1
    @vargonian deferred execution is the reason, read this thread: http://stackoverflow.com/questions/14057788/why-use-the-yield-keyword-when-i-could-just-use-an-ordinary-ienumerable – Kamil Budziewski Jan 13 '14 at 08:24
2

This is a more generic version that would work on any collection.

public static IEnumerable<T> SelectDescendents<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
{
        foreach(var item in source)
        {
            yield return item;
            foreach(T item2 in SelectDescendents(selector(item), selector))
                yield return item2;
        }
}

Usage

Persons.SelectDescendents(p => p.Children);
Magnus
  • 45,362
  • 8
  • 80
  • 118
  • How would this return the person itself ? Look at my structure please – Royi Namir Jan 16 '14 at 15:57
  • @RoyiNamir In you case since you don't have a collection of persons it would be: `new[]{ Person }.SelectDescendents(p => p. Children)` – Magnus Jan 16 '14 at 17:56