【问题标题】:identify circular parent/child records识别循环父/子记录
【发布时间】:2020-02-17 20:15:36
【问题描述】:

我正在尝试识别(然后在将来防止)List 对象中的父/子记录(将父子 ID 作为 SampleItem 类的整数属性)指向它们自己。
下面是 SampleItem 类和 SampleItem 对象列表:

public class SampleItem
    {
        public int ChildId{ get; set; }
        public int ParentId { get; set; }       
    }

List<SampleItem> items= new List<SampleItem>  
{
    new SampleItem{ ParentId=Null, ChildId=1 },
    new SampleItem{ ParentId=1, ChildId=2 },  
    new SampleItem{ ParentId=2, ChildId=4 },  
    new SampleItem{ ParentId=4, ChildId=1 }  
}; 

当我去扩展父/子关系时,它看起来像这样: 1--> 2 --> 4 --> 1(再次)--> 2(再次)--> 3(再次)...重复...(1是所有的根/父)

SampleItems 列表对象就像一个不允许循环引用的树状结构。

如何识别这些循环关系以及如何在 c# 代码中防止它们?如果有人能回答这个问题,我将不胜感激。

【问题讨论】:

  • 您可以使用一个简单的规则,即ChildId 始终必须大于ParentId
  • 你会考虑重新设计你的方法,而不是跟踪整数 ID,而是跟踪对父和子 SampleItem 对象的引用?
  • ChildId 不一定总是大于 ParentID。 ChildID 可能会小于 ParentID。在这里,我想检查父/子记录中是否存在任何循环引用。 SampleItems 列表对象就像一个不允许循环引用的树结构。 @JSteward
  • 似乎您实际上是在检查链表中的循环。正常的方法是有两个不同的指针指向你的起始项目,然后一次增加第一个,一次增加第二个。如果更快的增量返回 null,则不存在这样的循环。如果它们都是同一个节点,那么循环确实存在。
  • @JonathonChase 您能否为您解释的方法添加代码示例?我真的很感激。我相信您的方法是解决我的问题的正确方法。

标签: c# .net linq


【解决方案1】:

这本质上是确定链表是否有循环。解决这个问题的正常方法是以两种不同的速度在列表中递增,并查看节点是否相等,或者更快递增的节点是否已耗尽列表。对您的基类稍作修改以允许 null 值,

public class SampleItem
{
    public int ChildId { get; set; }
    public int? ParentId { get; set; }
}

以下快速而肮脏的实现将确定您的集合是否具有SampleItem 列表的循环。这确实假设关系是一对一的,在您的示例中,而不是一对多,因为这需要涵盖每个潜在孩子的情况。

void Main()
{
    List<SampleItem> itemsWithCycle = new List<SampleItem>
    {
        new SampleItem{ ParentId=null, ChildId=1 },
        new SampleItem{ ParentId=1, ChildId=2 },
        new SampleItem{ ParentId=2, ChildId=4 },
        new SampleItem{ ParentId=4, ChildId=1 }
    };
    List<SampleItem> itemsWithoutCycle = new List<SampleItem>
    {
        new SampleItem{ ParentId=null, ChildId=1 },
        new SampleItem{ ParentId=1, ChildId=2 },
        new SampleItem{ ParentId=2, ChildId=4 },
        new SampleItem{ ParentId=4, ChildId=5 }
    };

    Console.WriteLine(HasCycle(itemsWithCycle)); // true
    Console.WriteLine(HasCycle(itemsWithoutCycle)); // false


    bool HasCycle(IEnumerable<SampleItem> items) {
        var slow = items.FirstOrDefault(i => i.ParentId == null);
        var fast = slow;

        while(fast != null) {
            fast = Next(Next(fast));
            slow = Next(slow);

            if(fast == slow && fast != null) return true;
        }
        return false;

        SampleItem Next(SampleItem item)
        {
            if(item == null) return null;

            return items.FirstOrDefault(i => i.ParentId == item.ChildId);
        }
    }
}

【讨论】:

  • 可以是一对多。我的意思是一个父母可以有很多孩子。在这种情况下我需要做任何额外的步骤吗?@JonathonChase
猜你喜欢
  • 2014-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-03
相关资源
最近更新 更多