0

I have a simple class with a tree structure like this

public class Item
{
    public int ID { get; set; }
    public List<Item> Items { get; set; }  
}

with some sample data like this

//     [1]
//    / | \
//  [2][3][4]
//     / \
//    [5][6]

Item alt = new Item()
{
    ID = 1,
    Items = new List<Item>() {
    new Item() { ID = 2 }, new Item() {
        ID = 3, Items = new List<Item>() {
            new Item() { ID = 5 },
            new Item() { ID = 6 }
        }
    },
    new Item() { ID = 4 }
    }   
};

now I want to flatten the result into a array with all child nodes (except root node) to the end expected result:

[2]
[3][5]
[3][6]
[4]

I've tried something like

public static IEnumerable<IEnumerable<Item>> Flatten(Item alt)
{
    if (alt.Items != null)
        foreach (var altsub in alt.Items)
            yield return Flatten(altsub);
}

but that doesn't seem to work as expected. Any suggestions?

9
  • How deep can the tree go? Commented Dec 9, 2020 at 6:49
  • @mjwills the depth is n (unlimited) Commented Dec 9, 2020 at 6:50
  • Basically you want to do a breadth first iteration using Queue, then add the results to a list as you pop them off, convert to an array and your done Commented Dec 9, 2020 at 6:51
  • @Dr.Snail: your expected result contains duplicates (node 3 presents 2 times). Is this OK? Commented Dec 9, 2020 at 7:18
  • @Dennis yes, the result are all possible paths to the end Commented Dec 9, 2020 at 7:18

1 Answer 1

4

Here you go:

public static IEnumerable<IEnumerable<Item>> Flatten(Item alt)
{
    IEnumerable<IEnumerable<Item>> Flatten(Item[] a)
    {
        if (a.Last().Items == null)
        {
            yield return a;
        }
        else
        {
            foreach (var c in a.Last().Items)
                foreach (var x in Flatten(a.Concat(new [] { c }).ToArray()))
                    yield return x;
        }
    }

    if (alt.Items != null)
    {
        foreach (var c in alt.Items)
            foreach (var x in Flatten(new [] { c }))
                yield return x;
    }
}

Given your sample input you can run it like this:

Console.WriteLine(
    String.Join(
        Environment.NewLine,
        Flatten(alt).Select(xs =>
            String.Concat(xs.Select(x => $"[{x.ID}]")))));

That gives me:

[2]
[3][5]
[3][6]
[4]
Sign up to request clarification or add additional context in comments.

3 Comments

you seem to be a senior developer - would you say that was easy or advanced to solve?
@Dr.Snail - I've done this kind of thing before. It wasn't hard to solve. I also code in Prolog for fun - and this had a Prolog-ish kind of bent to it.
Nice work, I had a solution with a stack on the run, but had to leave work, but this is much better +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.