“家谱”数据结构

发布于 2024-09-11 05:29:03 字数 456 浏览 1 评论 0原文

我正在寻找一种在 PHP 中表示家谱的方法。这意味着孩子需要从两个(或更多)父母那里继承。

以下是要求:

  • 1、2 或更多父母
  • 如果我可以附加姓氏或关系状态等元数据,则可获得奖励积分

这是我的非工作尝试(遗憾的是,没有数组作为键):

$tree = array(
    'uncle' => false, // no children
    array('mom', 'dad') => array(
        'me' => false,
        array('brother', 'sister-in-law') => array(
            'niece' => false
        )
    )
);

问题是,我如何表示具有这些要求的家谱?

I'm looking for a way to represent a family tree in PHP. This means that children will need to inherit from two (or more) parents.

Here are the requirements:

  • 1, 2, or more parents
  • Bonus points if I can attach metadata like a last name or relationship status

Here is my non-working attempt (no arrays as keys, sadly):

$tree = array(
    'uncle' => false, // no children
    array('mom', 'dad') => array(
        'me' => false,
        array('brother', 'sister-in-law') => array(
            'niece' => false
        )
    )
);

The question is, how can I represent a family tree with these requirements?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

逆蝶 2024-09-18 05:29:03

您将无法像这样在一个 array() 中完成所有操作。您可以像这样设置树,但是设置具有多个父级和其他关系的更复杂的图需要多行代码。

如果你在这方面投入一些面向对象的知识,将会有很大帮助。让我们创建一个 Person 类来帮助管理关系。从根本上来说,我们已经有了人和他们与其他人的关系,所以我们将从这里开始。

Person 类

我想象的是每个人都有一系列的关系。该数组将首先按关系类型进行索引,例如“父母”或“孩子”。每个条目将是一个 Person 数组。

class Person {
    var $name, $relations;

    function __construct($name) {
        $this->name      = $name;
        $this->relations = array();
    }

    function addRelation($type, $person) {
        if (!isset($this->relations[$type])) {
            $this->relations[$type] = array();
        }

        $this->relations[$type][] = $person;
    }

    // Looks up multiple relations, for example "parents".
    function getRelations($type) {
        if (!isset($this->relations[$type])) {
            return array();
        }

        return $this->relations[$type];
    }

    // Looks up a single relation, for example "spouse".
    function getRelation($type) {
        $relations = $this->getRelations($type);
        return empty($relations) ? null : $relations[0];
    }

    function __toString() {
        return $this->name;
    }

友好的加法器和获取器

以上述为基础,我们可以添加一些更友好命名的方法。为了便于说明,我们将处理父母/子女关系和配偶。

    function addParents($mom, $dad) {
        $mom->addChild($this);
        $dad->addChild($this);
    }

    function addChild($child) {
        $this ->addRelation('children', $child);
        $child->addRelation('parents',  $this);
    }

    function addSpouse($spouse) {
        $this  ->addRelation('spouse', $spouse);
        $spouse->addRelation('spouse', $this);
    }

    function getParents () { return $this->getRelations('parents');  }
    function getChildren() { return $this->getRelations('children'); }
    function getSpouse  () { return $this->getRelation ('spouse');   }
}

创建人员

现在我们可以创建几个人并设置他们的关系。让我们试试比利和他的父母约翰和简。

$john  = new Person('John');
$jane  = new Person('Jane');
$billy = new Person('Billy');

$john ->addSpouse ($jane);
$billy->addParents($jane, $john);

我们可以像这样检查它们的关系:

echo "John is married to " . $john->getSpouse() . ".\n";
echo "Billy's parents are " . implode(" and ", $billy->getParents()) . ".\n";

输出:

约翰与简结婚了。
比利的父母是简和约翰。

显示家谱

如果图变大,我们可以递归遍历该图。这是一个示例树遍历函数,它显示了基本的家谱。我将萨拉、她的丈夫迈克和他们的儿子鲍比也加入其中。

$john  = new Person('John');
$jane  = new Person('Jane');
$sara  = new Person('Sara');
$mike  = new Person('Mike');
$bobby = new Person('Bobby');
$billy = new Person('Billy');

$john ->addSpouse ($jane);
$sara ->addParents($jane, $john);
$sara ->addSpouse ($mike);
$bobby->addParents($sara, $mike);
$billy->addParents($jane, $john);

function displayFamilyTree($root, $prefix = "") {
    $parents = array($root);

    if ($root->getSpouse() != null) {
        $parents[] = $root->getSpouse();
    }

    echo $prefix . implode(" & ", $parents) . "\n";

    foreach ($root->getChildren() as $child) {
        displayFamilyTree($child, "....$prefix");
    }
}

displayFamilyTree($john);

输出:

约翰和约翰简
....萨拉&迈克
........鲍比
....比利


编辑:下面是 @Wrikken 的评论,为了可读性而转载:

确实是关于它。恕我直言,为每个关系添加一个起始日期(可能为 NULL,表示没有结束)。离婚、收养等都会发生。另外:我会添加一个反向类型& “ping-back”到 addRelation() 函数:

function addRelation($type, $person, $reverseType, $pingback = false) {
    if (!isset($this->relations[$type])) {
        $this->relations[$type] = array();
    }

    if (!in_array($person, $this->relations[$type], true)) {
        $this->relations[$type][] = $person;
    }

    if (!$pingback) {
        $person->addRelation($reverseType, $this, $type, true);
    }
}

You won't be able to do it all in a single array() like that. You can set up trees like that, but setting up more complicated graphs with multiple parents and other relations requires multiple lines of code.

It'll help a lot if you throw some OO at this. Let's create a Person class to help manage the relationships. Fundamentally, we've got people and their relationships with other people, so we'll start there.

Person class

What I imagine is each person having an array of relationships. This array will be indexed first by the type of relationship, for example "parents" or "children". Each entry will then be an array of Persons.

class Person {
    var $name, $relations;

    function __construct($name) {
        $this->name      = $name;
        $this->relations = array();
    }

    function addRelation($type, $person) {
        if (!isset($this->relations[$type])) {
            $this->relations[$type] = array();
        }

        $this->relations[$type][] = $person;
    }

    // Looks up multiple relations, for example "parents".
    function getRelations($type) {
        if (!isset($this->relations[$type])) {
            return array();
        }

        return $this->relations[$type];
    }

    // Looks up a single relation, for example "spouse".
    function getRelation($type) {
        $relations = $this->getRelations($type);
        return empty($relations) ? null : $relations[0];
    }

    function __toString() {
        return $this->name;
    }

Friendly adders and getters

With the above as a foundation we can then add some friendlier-named methods. For illustration we'll handle the parent/child relation and spouses.

    function addParents($mom, $dad) {
        $mom->addChild($this);
        $dad->addChild($this);
    }

    function addChild($child) {
        $this ->addRelation('children', $child);
        $child->addRelation('parents',  $this);
    }

    function addSpouse($spouse) {
        $this  ->addRelation('spouse', $spouse);
        $spouse->addRelation('spouse', $this);
    }

    function getParents () { return $this->getRelations('parents');  }
    function getChildren() { return $this->getRelations('children'); }
    function getSpouse  () { return $this->getRelation ('spouse');   }
}

Creating people

Now we can create a couple of people and setup their relationships. Let's try Billy and his parents John and Jane.

$john  = new Person('John');
$jane  = new Person('Jane');
$billy = new Person('Billy');

$john ->addSpouse ($jane);
$billy->addParents($jane, $john);

And we can check out their relationships like so:

echo "John is married to " . $john->getSpouse() . ".\n";
echo "Billy's parents are " . implode(" and ", $billy->getParents()) . ".\n";

Output:

John is married to Jane.
Billy's parents are Jane and John.

Display family tree

We can traverse the graph recursively if it grows bigger. Here's an example tree-walking function which displays a rudimentary family tree. I've added Sara, her husband Mike, and their son Bobby to the mix.

$john  = new Person('John');
$jane  = new Person('Jane');
$sara  = new Person('Sara');
$mike  = new Person('Mike');
$bobby = new Person('Bobby');
$billy = new Person('Billy');

$john ->addSpouse ($jane);
$sara ->addParents($jane, $john);
$sara ->addSpouse ($mike);
$bobby->addParents($sara, $mike);
$billy->addParents($jane, $john);

function displayFamilyTree($root, $prefix = "") {
    $parents = array($root);

    if ($root->getSpouse() != null) {
        $parents[] = $root->getSpouse();
    }

    echo $prefix . implode(" & ", $parents) . "\n";

    foreach ($root->getChildren() as $child) {
        displayFamilyTree($child, "....$prefix");
    }
}

displayFamilyTree($john);

Output:

John & Jane
....Sara & Mike
........Bobby
....Billy


Edit: Here's @Wrikken's comment below, reproduced for readability:

About it indeed. IMHO add a from-until date to every relationship though (possibly NULL for no end). Divorces happen, as do adoptions, etc. Also: I'd add a reverse types & 'ping-back' to the addRelation() function:

function addRelation($type, $person, $reverseType, $pingback = false) {
    if (!isset($this->relations[$type])) {
        $this->relations[$type] = array();
    }

    if (!in_array($person, $this->relations[$type], true)) {
        $this->relations[$type][] = $person;
    }

    if (!$pingback) {
        $person->addRelation($reverseType, $this, $type, true);
    }
}
段念尘 2024-09-18 05:29:03

GEDCOM 是一个开放规范,用于在不同的家谱软件之间交换家谱数据。 GEDCOM 文件是纯文本(通常是 ANSEL 或 ASCII),包含有关个人的家谱信息以及将这些记录链接在一起的元数据。大多数家谱软件支持导入和/或导出为 GEDCOM 格式。

使用 GEDCOM 的一个主要优点是您可以使用桌面程序,例如 Aldfaer(仅限荷兰语)Gramps 或 < a href="http://www.legacyfamilytree.com/paf.asp" rel="nofollow">Legacy Family Tree 以及 Geneanet 构建或修改您的家谱并将其与其他人的家谱进行比较。

使用 GEDCOM 格式的另一个主要优点是,您可以使用多种编程语言的库来保存和加载数据。 PHP 库的示例为 GEDCOM Import/Export-FilterGenealogyGedcomPHP GEDCOM

使用 PHP GEDCOM,读取和解析 GEDCOM 文件将像这样简单:

$parser = new \PhpGedcom\Parser();
$gedcom = $parser->parse('gedcom.ged');

使用 GEDCOM 的一个主要缺点是 GEDCOM 的数据格式是围绕核心系列构建的,这意味着该标准在支持非传统方面受到限制家庭结构,如同性伴侣、混合家庭或同居。虽然可以扩展 GEDCOM 以支持这种类型的关系,但不同软件之间的互操作性对于此类扩展来说是有限的。

使用 GEDCOM 的另一个主要缺点是 GEDCOM 文件是整体的。如果您有数千人的数据集或者您想要频繁更改数据结构,则可能会遇到性能问题。特别是在这些情况下,最好将数据存储在数据库中。不过,这并不意味着 GEDCOM 毫无用处。在这些情况下,您可能需要考虑使用基于 GEDCOM 格式的数据库架构,该架构允许您在数据库和 GEDCOM 格式之间导入/导出。为此,图书馆也存在。 Oxy-Gen 就是一个例子。


GEDCOM 的替代方案是 GenTech 数据模型Gramps 数据模型。虽然它们不如 GEDCOM 标准那么常用,但它们可能更适合您的需求。

如果你想使用 Gramps 数据模型,你可以使用例如。 Gramps PHP 导出器 将数据导出到 SQLite 数据库。另请参阅此来源了解如何设计您的数据库适合 Gramps 数据模型。

GEDCOM is an open specification for exchanging genealogical data between different genealogy software. A GEDCOM file is plain text (usually either ANSEL or ASCII) containing genealogical information about individuals, and meta data linking these records together. Most genealogy software supports importing from and/or exporting to GEDCOM format.

A major advantage of using GEDCOM, would be that you could use desktop programs like Aldfaer (Dutch only), Gramps or Legacy Family Tree as well as online tools like Geneanet to build or modify your family tree and compare it with the family trees of others.

Another major advantage of using the GEDCOM format, is that there are libraries in multiple programming language at your disposal to save and load your data. Examples of PHP libraries would be GEDCOM Import/Export-Filter, GenealogyGedcom or PHP GEDCOM.

Using PHP GEDCOM, reading and parsing a GEDCOM file would be as simple as this:

$parser = new \PhpGedcom\Parser();
$gedcom = $parser->parse('gedcom.ged');

A major disadvantage of using GEDCOM, is that GEDCOM's data format is built around the nuclear family, which means that the standard is limited in its support of non-traditional family structures, like same-sex partnerships, blended families or cohabitation. While it is possible to extend GEDCOM to support this type of relationships, inter-operability between different software is limited for such extensions.

Another major disadvantage of using GEDCOM, is that GEDCOM files are monolithic. If you have a dataset of thousands of people or your want to frequently change your data structure, you're likely to experience performance problems. Especially in those cases, it's best to store your data in a database instead. Still, that doesn't mean GEDCOM is useless. In those cases, you might want to consider using a database schema based on the GEDCOM format that allows you to import/export between your database and the GEDCOM format. For this, libraries exist as well. Oxy-Gen would be an example.


Alternatives to GEDCOM would be GenTech's data model or Gramps data model. While they aren't as commonly used as the GEDCOM standard, they might better suit your needs.

If you want to use the Gramps data model, you can use eg. the Gramps PHP exporter to export your data into an SQLite database. See also this source on how to design your database to be suitable for the Gramps data model.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文