使用图表建模家庭关系

the*_*man 2 language-agnostic algorithm tree graph data-structures

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

我试图模拟这样的事情,其中​​相关实体(人)之间存在边缘以表示关系。

在此处输入图片说明

这就是我开始的方式。

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>();
}
Run Code Online (Sandbox Code Playgroud)

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

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

现在说到挽回关系,比如找兄弟姐妹、舅舅等等。我有点必须手动导航边缘才能为每种类型的关系找到合适的人。对于每段关系,我都必须这样做。

例如,为了找到我的侄女,我必须穿越到我妈妈那里找到我的兄弟姐妹并得到他们的孩子,

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

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

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

我在想是否有更好的方法来对此进行建模,以及是否有更好的方法来编写提取关系。

Jim*_*hel 5

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

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

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

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

对此进行建模的最灵活的方法是拥有一个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
Run Code Online (Sandbox Code Playgroud)

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

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

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

  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)
Run Code Online (Sandbox Code Playgroud)

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

编码它变成了编写四个内在函数(ParentsChildrenSiblingsSpouse)的问题,每个函数都IEnumerable<PersonId>将 an作为参数并返回 an IEnumerable<PersonId>,然后组合这些函数。该Siblings函数必须从结果中排除输入参数中的任何值。考辛斯变成了:

var person = new List<PersonId> {personId};
var cousins = person.Parents().Siblings().Children();
Run Code Online (Sandbox Code Playgroud)

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

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

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

brother - (siblings male)
grandmother - (parents parents female)
maternal-uncle - (parents female siblings male)
spouse-step-sister - (spouse siblings step female)
Run Code Online (Sandbox Code Playgroud)