-2

I want to ask you what's the most efficient way of going through each child object of a Parent. For example I have a class which is:

public class Asset
{
    public string Id { get; set; }

    public Asset Child { get; set; }
}

static void Main(string[] args)
{
     var x = new Asset() { Id = "1" };
     var y = new Asset() { Id = "2" };
     var z = new Asset() { Id = "3" };

     x.Child = y;
     y.Child = z;
     z.Child = null;

     var listOfChildItems = new List<Asset>();
     listOfChildItems = GetAllChildren(x);
}

static List<Asset> GetAllChildren(Asset asset)
{
   // TODO:
}

This class might contain Child which contains another child and so on. So what I want is to obtain whole list of Child items of Child items recursively until Child item is not equal null.

pjrki
  • 248
  • 1
  • 3
  • 15

4 Answers4

4
class Asset
{
    public Asset Child { get; set; } = null;
}

static void main (string[] args) 
{
     List<Asset> children = new List<Asset>();
     Asset asset = new Asset();
     while (asset.Child != null) 
     {
         asset = asset.Child;
         children.Add(asset);
     }
     //asset is now the bottom most child
}
Dan Scott
  • 554
  • 3
  • 10
  • @Fildor how do you figure that one? It checks to see if the child is null, assigns the asset to be the child that is not `null` and then adds it to `children` – Dan Scott Aug 24 '18 at 14:09
1
static IEnumerable<Asset> GetAllAssets(Asset asset)
{
    if (asset == null)
        yield break;

    yield return asset;
    foreach (Asset child in GetAllAssets(asset.Child))
        yield return child;
}
  • This is not the most efficient way. I will say this is the less efficient way due to recursion, yield returns, and foreach loop. – Michał Jarzyna Aug 24 '18 at 14:08
  • @MichałJarzyna why do you like it? take a look: https://stackoverflow.com/questions/410026/proper-use-of-yield-return – Dongdong Aug 24 '18 at 14:21
  • @Dongdong because it should be `public static IEnumerable GetAllAssets( Asset item ) { while( item.Child != null ) { item = item.Child; yield return item; } }` – Fildor Aug 24 '18 at 14:23
  • Oh.Just Edit it.:-) – Dongdong Aug 24 '18 at 14:24
  • @Dongdong No, I won't. That would vandalize Matthias' answer. And I don't know if he would be ok with it. – Fildor Aug 24 '18 at 14:26
0
public class Asset
{
    public Asset Child { get; set; }

    public List<Asset> GetChildren()
    {
        return GetChildrenInternal(new List<Asset>(), this);
    }

    private List<Asset> GetChildrenInternal(List<Asset> children, Asset parent)
    {
        if (parent.Child?.Child != null)
        {
            children.Add(parent.Child);
            GetChildrenInternal(children, parent.Child);
        }

        return children;
    }
}
J. Aguilar
  • 194
  • 5
  • IMHO, a recursive solution is suboptimal here. You can do without it _and_ be more efficient and readable and shorter at the same time. – Fildor Aug 24 '18 at 14:43
0
public static IEnumerable<T> GatherChild<T>(this T value, Func<T, T> selector)
    where T : class
{
    while (!(value is null))
    {
        yield return value;
        value = selector(value);
    }
}

public static IEnumerable<T> GatherSelfAndChildren<T>(this T value, Func<T, IEnumerable<T>> selector) => 
    selector(value).SelectMany(x => GatherSelfAndChildren(x, selector)).Prepend(value);

public static IEnumerable<T> GatherChildren<T>(this T value, Func<T, IEnumerable<T>> selector) => 
    selector(value).SelectMany(x => x.GatherSelfAndChildren(selector));
shtse8
  • 1,092
  • 12
  • 20