Impostor
Impostor

Reputation: 2050

Convert a nested object into a array

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?

Upvotes: 0

Views: 250

Answers (1)

Enigmativity
Enigmativity

Reputation: 117064

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]

Upvotes: 4

Related Questions