【问题标题】:Modeling family relationships using a graph使用图表建模家庭关系
【发布时间】:2023-03-12 00:14:01
【问题描述】:

我正在尝试将家庭关系建模为图表,以便我可以查询它们以查找关联关系和其他关系。这是一个练习练习,所以我不能使用现有的解决方案,如图形数据库等。

我正在尝试模拟这样的东西,其中相关之间存在边缘 实体(人)来表示关系。

我就是这样开始的。

public class Person
{
    public string Name { get; set; }
    List<IEdge> Children { get; set; }
    IEdge Spouse { get; set; }
    IEdge Father { get; set; }
    IEdge Mother { get; set; }
}

public class Edge
{
    Person From { get; set; }
    Person To { get; set; }
    public string RelationshipType { get; set; }
}
public class Family
{
    Dictionary<string, Person> familyGraph = new Dictionary<string, Person>();
}

邻接表表示将存储在一个键值对中,一个人的所有边都将存储在相应的人节点中。

因此添加与 this 的关系很简单。

现在说到检索关系,比如找出兄弟姐妹、舅舅等等。我有点不得不手动导航边缘以找到每种关系类型的合适人选。对于每一种关系,我都必须这样做。

例如,为了找到我的侄女,我将不得不遍历我的妈妈找到我的兄弟姐妹并得到他们的孩子,

为了找到我的岳母。我必须穿越到我的妻子那里找到她的妈妈。 我在想这就是代码在这个数据结构中的样子

List<string> FindNeice(string username)
{
    currentPerson = GerPerson(username)
    siblings = currentPerson.Mother.Children;
    niece = siblings.Where(mbox => mbox.Gender == "F").SelectMany(m => m.Children);
}

所以这必须存在于每一种关系中。是的,有些可以重复使用,因为母/父关系与您和您妻子之间交换的起始人相同。

我正在考虑是否有更好的方法来对此建模以及编写提取关系的更好方法。

【问题讨论】:

  • 了解Prologniece 的示例
  • 您可以随时在图表中添加更多边以捕获其他关系。

标签: algorithm data-structures graph tree language-agnostic


【解决方案1】:

家庭关系看似很简单,但很快就变得复杂起来。你提到了姻亲关系(你是妻子的母亲),但更亲密的关系是复杂的。例如,考虑兄弟姐妹。技术上:

  • 兄弟姐妹是指与您共享同一亲生母亲父亲的人。
  • 同父异母兄弟姐妹是指与您共享同一亲生母亲父亲的人。
  • 继兄弟姐妹是指其亲生母亲或父亲与您的亲生母亲或父亲结婚的人。

甚至不要让我开始收养关系。

但是,让我们暂时把这些复杂性放在一边,假设一个没有继兄弟、同父异母姐妹等的世界:一个简单的家谱。

对此进行建模的最灵活方法是创建一个包含有关该人的信息但不包含任何关系的Person 记录。例如,该信息将是姓名、出生日期等。并且该人具有永远不会改变的唯一标识符。比如说,一个 64 位的数字。您有一个包含 Person 记录的大表。

您还有一个包含Relationship 记录的大表。每条记录都包含源、目标和关系类型。有两种类型的关系:父母和配偶。

(我故意将性别关系排除在这个简单的示例之外,因为包含它会增加不必要的复杂性,而当前关于性别认同的社会讨论使它变得更加复杂。)

因此,如果您的直系亲属由您(乔治)、您的父母(玛丽和戴夫)以及您的两个兄弟姐妹(鲍勃和莎莉)组成,那么关系是:

Mary, George, Parent
Dave, George, Parent
Mary, Bob, Parent
Dave, Bob, Parent
Mary, Sally, Parent
Dave, Sally, Parent
Mary, Dave, Spouse
Dave, Mary, Spouse

读作“玛丽是乔治的父母”。

请注意,关于是否最好包括互惠配偶关系存在一些争论。我将它们包括在这里是因为这样更容易推理。

所以如果你想找到一个人的兄弟姐妹,你可以这样做:

  1. 在关系表中查询该人的 ID 为目标的所有关系,以及关系父级的类型。这会为您提供此人父母的标识符列表。
  2. 在关系表中查询父项标识符之一为源且关系类型为父项的所有关系。这为您提供了所有父母子女的清单。该列表将包括原始人以及所有父母的孩子:根据定义,原始人的兄弟姐妹。

然后,您可以选择是要为更复杂的关系编写代码,还是为这些关系开发类似脚本的简单定义。考虑:

parents - intrinsic function
children - intrinsic function
spouse - intrinsic function
siblings - (parents children) (probably should be an intrinsic, to eliminate self)
grandparents - (parents parents)
uncles/aunts - (parents siblings)
cousins - (parents siblings children)
parents-in-law - (spouse parents)
siblings-in-law - (spouse siblings)
nieces/nephews - (siblings children) + (siblings-in-law children)

鉴于父母/子女和配偶/配偶关系,您可以轻松编写查询以查找任何其他类型的家庭关系。编写代码来执行这些查询非常容易,并且您可以消除尝试手动编写代码时遇到的各种问题。

编码变成了编写四个内部函数(ParentsChildrenSiblingsSpouse)的问题,每个函数都将 IEnumerable&lt;PersonId&gt; 作为参数并返回 IEnumerable&lt;PersonId&gt; ,然后组合这些函数。 Siblings 函数必须从结果中排除输入参数中的任何值。表亲变成:

var person = new List<PersonId> {personId};
var cousins = person.Parents().Siblings().Children();

编写代码以根据我描述的简单查询定义生成这些查询并不是非常困难。或者,如果您更愿意使用静态关系,您可以为每个关系编写单独的函数。

现在,如果您想将其扩展到继兄弟姐妹、同父异母兄弟姐妹等,您保持相同的基本关系并添加更多信息,例如关系子类型。您仍然会查询基本的父/子关系,但如果需要,然后过滤掉“steps”和“halfs”或其他子类型。对于性别关系,只需将性别添加到 Person 记录。对于姐妹,查询兄弟姐妹并过滤结果以仅包含女性。

现在,如果您想扩展您的查询定义以包含性别,它会变成这样:

brother - (siblings male)
grandmother - (parents parents female)
maternal-uncle - (parents female siblings male)
spouse-step-sister - (spouse siblings step female)

【讨论】:

  • 这很好地解决了问题。我在想是否有更好的方法可以在不扫描整个关系表的情况下找到某人自己的父母。如果我们保持某种互惠的父母关系,我们也许可以做到。
  • @thebenman 避免扫描整个表的方法是建立索引。这样当您查询父母时,它只会查看目标 id 为您的 id 的关系。关系数据库使这对您来说几乎是透明的。如果您想在代码中执行此操作,请构建一个Dictionary&lt;int, List&lt;Relationship&gt;&gt;,其中键是目标 id,值是关系列表,其中该 id 是目标。您可能还需要用于源关系的单独字典。或者,您可以将它们结合起来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多