使用图表建模家庭关系

时间:2019-06-10 00:30:01

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

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

我正在尝试对类似的东西进行建模,其中在相关之间存在一条边 实体(人)表示关系。

enter image description here

这就是我的入门方式。

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

邻接表表示将存储在键,值对中,并且来自人的所有边都将存储在相应的“人”节点中。

因此添加关系很简单。

现在,在找回关系时,例如找出兄弟姐妹,母叔叔等。我有点必须手动导航边缘以找到适合每种关系类型的合适人员。对于每种关系,我都必须做同样的事情。

例如,要找到我的外nie女,我必须走遍我的妈妈,找到我的兄弟姐妹并带上他们的孩子,

寻找我的岳母。我必须去找我的妻子找妈妈。 我在想这就是这种数据结构的代码

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

因此每个关系都必须存在。是的,有些可以重用,因为母子关系与您和妻子之间交换的始作俑者相同。

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

1 个答案:

答案 0 :(得分: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)的问题,每个函数都以{ {1}}并返回IEnumerable<PersonId>,然后组合这些函数。 IEnumerable<PersonId>函数必须从结果中排除输入参数中的任何值。表兄弟变成:

Siblings

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

现在,如果要将其扩展到同级兄弟姐妹,半兄弟姐妹等,则可以保持相同的基本关系并添加更多信息,例如关系子类型。您仍然会查询基本的父/子关系,但是如果需要,可以过滤掉“步骤”和“半”或其他子类型。对于性别关系,只需将性别添加到var person = new List<PersonId> {personId}; var cousins = person.Parents().Siblings().Children(); 记录中。对于姐妹,请查询同级并将结果过滤为仅包括雌性。

现在,如果您想扩展查询定义以包括性别,它将变成:

Person