【问题标题】:Finding parents in a tree hierarchy for a given child LINQ (lambda expression)在给定子 LINQ(lambda 表达式)的树层次结构中查找父级
【发布时间】:2020-04-21 01:43:24
【问题描述】:

我有关于父子关系的数据,使用 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 表达式)进行反向遍历并找到所有父级。

【问题讨论】:

  • “所有父母”是什么意思?你的意思是父母和父母的父母......?
  • 是的,如果给出了 ID 4,我应该反向遍历并获取所有元素:在这种情况下,对于 ID =4,它的父母应该是 3,2,1。谢谢
  • 我不确定您是否可以单独使用 LINQ 解决此问题。你需要某种递归。

标签: c# linq lambda


【解决方案1】:

你可以使用递归来做这样的事情:

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&lt;int,FlatData&gt; 来加快获取FlatData 对象(因为它是Id)。

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

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

【讨论】:

  • 谢谢 Yacoub 欣赏它,我们预计现在有 23000 条记录的大型数据集,随着我们添加记录,这可能会增长。你能发布字典的解决方案吗
  • @VijenderReddyChintalapudi,如果这回答了您的问题,请考虑将其标记为答案
  • @YacoubMassad 您的解决方案非常完美。但是,我的要求恰恰相反。我需要递归地找到所有孩子。我该如何做到这一点?
  • @corix010,在 cmets 中很难回答这个问题。尝试自己做,如果失败,请提出问题。
  • @YacoubMassad 我尝试修改您的方法,但只能在一个分支中获取所有后代。请看我的问题 -> stackoverflow.com/questions/37441398/…
【解决方案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),那么我会得到这个结果:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多