mrblah
mrblah

Reputation: 103487

Recursive call return a List, return type causing me issues

I have a recursive method that returns categories, and checks for its sub categories.

This is my code:

public List<Category> GetAllChildCats(int categoryid) 
{
    List<Category> list = new List<Category>();

    Category c = Get(categoryid);

    foreach(Category cat in c.ChildCategories) 
    {
        list.Add(GetAllChildCats(cat.CategoryID));
    }

}

This fails because the call to list.Add() expects a Category object, but GetAllChildCats() returns List<Category>

How should I work around this?

Upvotes: 21

Views: 26900

Answers (5)

Akli
Akli

Reputation: 1539

Here's a modified version of Jon Skeet's answer using a local method (C# 7) :

    public List<Category> GetAllChildCats(int rootId)
    {
        List<Category> list = new List<Category>();
        Traverse(rootId);
        return list;

        void Traverse(int categoryId)
        {
            Category c = Get(categoryId);
            list.Add(c);

            foreach (Category cat in c.ChildCategories)
            {
                Traverse(cat.CategoryID);
            }
        }
    }

Upvotes: 1

Rit
Rit

Reputation: 21

I had the same problem before. Here is the way I solved it:

public void GetAllChildCategories(ProductCategory ParentCategory)
{
    ParentCategory.ChildCategories = GetChildCategories(ParentCategory.ID);

    foreach(ProductCategory cat in ParentCategory.ChildCategories)
    {
        GetAllChildCategories(cat);
    }
}

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1500055

Currently you haven't shown anything which actually adds a single category to the list... I'm assuming that as you recurse, you want to add the results of Get(categoryId) as well·

Preet's solution will certainly work, but here's an alternative which avoids creating all the extra lists:

public List<Category> GetAllChildCats(int categoryId)
{
    List<Category> ret = new List<Category>();
    GetAllChildCats(categoryId, ret);
    return ret;
}

private void GetAllChildCats(int categoryId, List<Category> list)
{
    Category c = Get(categoryid);
    list.Add(c);

    foreach(Category cat in c.ChildCategories)
    {
        GetAllChildCats(cat.CategoryID, list);
    }
}

This creates a single list, and adds items to it as it goes.

One point though - if you've already got the child Category objects, do you really need to call Get again? Does each child only contain its ID until you fetch the whole category?

Upvotes: 57

Lee
Lee

Reputation: 144126

I think this linq version will allow you to avoid the overhead of creating a list:

public IEnumerable<Category> GetAllChildCats(int categoryid)
{
    Category c = Get(categoryid);
    return new[] { c }.Concat(c.ChildCategories.SelectMany(cat => GetAllChildCats(cat)));
}

You can always call ToList() on the returned IEnumerable if you need it.

Upvotes: 2

Preet Sangha
Preet Sangha

Reputation: 65476

   foreach(Category cat in c.ChildCategories)
      {
              list.AddRange( GetAllChildCats(cat.CategoryID) )

      }

and don't forget the

return list;

Upvotes: 12

Related Questions