1

我有一个List<Category>地方Category是:

public class Category {
    public List<Category> Categories { get; set; } // this holds sub-categories
    public string Name { get; set; }
    public string Icon { get; set; }
    public string Id { get; set; }
}

由于Categories它本身是另一个List<Category>,因此它可以包含子类别,而这些子类别可以包含子类别,依此类推......

我知道我可以像这样查询第一个“层”:

Categories.Where(x => x.Categories.Any(c => c.Id == id)).FirstOrDefault();

如何有效地查询对象树中的特定层CategoryId可能是 3,4 或 5 层(最多有 3 层,但我想知道将来参考)?

编辑

Category此外,如果我只有Id3 层深的子类别,我怎么能得到整个对象树,一直到顶层?

4

3 回答 3

1

您可以编写如下扩展方法来展平CategoryIEnumerable<Category>

public static IEnumerable<Category> Flatten(this Category category)
{
    if (category.Categories != null)
    {
        foreach (var sub in category.Categories)
        {
            foreach (var subSub in sub.Flatten())
                yield return subSub;
        }
    }
    yield return category;
}

然后,您可以随意使用 Linq IEnumerable<Category>

var filtered = categoryList.SelectMany(x => x.Flatten())
                           .Where(x => x.Id == id);
于 2012-12-08T07:38:47.377 回答
1

这将递归地遍历类别,直到找到与传递的 id 匹配的类别(如果有)。将返回找到的类别的完整路径(即像面包屑菜单一样):

static IEnumerable<Category> GetById(IEnumerable<Category> categories, string id)
{
    if (categories == null || !categories.Any())
        yield break;

    Category result = categories.FirstOrDefault(c => c.Id == id);
    if (result != null)
    {
        yield return result;
        yield break;
    }

    foreach (var category in categories)
    {
        var subCategories = GetById(category.Categories, id);
        if (subCategories.Any()) // we have found the category
        {
            yield return category; // return current category first

            foreach (var subCategory in subCategories)                    
                yield return subCategory;                   

            yield break; // don't search in other categories
        }
    }
}

用法:

IEnumerable<Category> result = GetById(categories, id);
// Food > Beer > Kilkenny
string breadcrumbs = String.Join(" > ", result.Select(c => c.Name).ToArray());

如果您愿意,可以将此方法转换为扩展。

于 2012-12-08T08:40:37.503 回答
0

如果您有一个不确定的嵌套级别,您将需要递归Categories,即使您有一个固定的嵌套级别,对于任何超过 2-3 级的嵌套级别,都值得递归。

Linq 并没有真正表达递归的方法,尽管这篇文章谈到了使用 Linq2Xml 特性来实现它:Expressing recursion in LINQ

如果您能够修改类本身,则可以实现一个GetChildById-style 方法来递归地扫描 child Categories

于 2012-12-08T01:08:43.197 回答