在给定子项的树层次结构中查找父项LINQ(lambda表达式)

时间:2016-01-11 20:20:05

标签: c# linq lambda

我有父母子女关系的数据,找到给定父母的所有孩子都是直接使用Linq,但我有其他问题,在提供孩子时找到所有父母。

  List<FlatData> elements = new List<FlatData>
          {
   new FlatData {Id = 1, ParentId = NULL ,Text = "Apple"},
   new FlatData {Id = 2, ParentId = 1, Text = "Cat"},
   new FlatData {Id = 3, ParentId = 2, Text = "Dog"},
   new FlatData {Id = 4, ParentId = 3, Text = "Elephant"}
       };

当给出Id 4时,我需要能够反向遍历并使用LINQ(lambda表达式)查找所有父项,非常感谢任何帮助。

2 个答案:

答案 0 :(得分:7)

您可以使用递归来执行以下操作:

private IEnumerable<FlatData> FindAllParents(List<FlatData> all_data, FlatData child)
{
    var parent = all_data.FirstOrDefault(x => x.Id == child.ParentId);

    if (parent == null)
        return Enumerable.Empty<FlatData>();

    return new[] {parent}.Concat(FindAllParents(all_data, parent));
}

并像这样使用它:

int id = 4;

var child = elements.First(x => x.Id == id);

var parents = FindAllParents(elements, child).ToList();

此解决方案有效,但如果您拥有大型数据集,那么您应该考虑使用Dictionary<int,FlatData>来更快地获取FlatData对象,因为它是Id。< / p>

以下是该方法在这种情况下的样子:

private IEnumerable<FlatData> FindAllParents(Dictionary<int,FlatData> all_data, FlatData child)
{
    if(!all_data.ContainsKey(child.ParentId))
        return Enumerable.Empty<FlatData>();

    var parent = all_data[child.ParentId];

    return new[] {parent}.Concat(FindAllParents(all_data, parent));
}

以下是您将如何使用它:

var dictionary = elements.ToDictionary(x => x.Id); //You need to do this only once to convert the list into a Dictionary

int id = 4;

var child = elements.First(x => x.Id == id);

var parents = FindAllParents(dictionary, child).ToList();

答案 1 :(得分:2)

这有效:

var parents = elements.ToDictionary(x => x.Id, x => x.ParentId);

Func<int, IEnumerable<int?>> getParents = null;
getParents = i =>
    parents.ContainsKey(i)
        ? new [] { parents[i] }.Concat(parents[i].HasValue
            ? getParents(parents[i].Value)
            : Enumerable.Empty<int?>())
        : Enumerable.Empty<int?>();

如果我要求getParents(4),我会得到这个结果:

result

删除null父级的略微简化版本是:

var parents =
    elements
        .Where(x => x.ParentId != null)
        .ToDictionary(x => x.Id, x => x.ParentId.Value);

Func<int, IEnumerable<int>> getParents = null;
getParents = i =>
    parents.ContainsKey(i)
        ? new [] { parents[i] }.Concat(getParents(parents[i]))
        : Enumerable.Empty<int>();