LINQ通过IList中的几个对象“层”进行查询?

时间:2012-12-08 00:56:46

标签: c# linq

我有一个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();

如何在对象树中有效地查询特定Category Id,可能是3,4或5层(最多有3个,但为了将来参考我会想知道吗?

修改

此外,如果我只有3层深的子类别Category,我如何获得整个对象树,一直到顶级Id

3 个答案:

答案 0 :(得分:1)

您可以编写如下所示的扩展方法,将Category展平为IEnumerable<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;
}

然后根据需要在IEnumerable<Category>上使用Linq:

var filtered = categoryList.SelectMany(x => x.Flatten())
                           .Where(x => x.Id == id);

答案 1 :(得分:1)

这将递归遍历类别,直到找到类别匹配传递的id(如果有的话)。将返回找到的类别的完整路径(例如,像breadcrumbs菜单一样):

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());

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

答案 2 :(得分:0)

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

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

如果您能够修改类本身,则可以实现GetChildById样式方法来递归扫描子Categories