【问题标题】:sort multidimensional array by 'parent/child' relationship按“父/子”关系对多维数组进行排序
【发布时间】:2020-06-11 10:28:49
【问题描述】:
I have an array that looks like this:


[0] => Array
    (
        [id] => 111
        [parent_id] => 222
        [field_1] => Main document
    )
[1] => Array
    (
        [id] => 123
        [parent_id] => 222
        [field_1] => Main document
    )
[2] => Array
    (
        [id] => 777
        [parent_id] => 111
        [field_1] => Child document
    )
[3] => Array
    (
        [id] => 345
        [parent_id] => 222
        [field_1] => Main document
    )
[4] => Array
    (
        [id] => 789
        [parent_id] => 123
        [field_1] => Child document
    )
[5] => Array
    (
        [id] => 567
        [parent_id] => 345
        [field_1] => Child document
    )

如您所见,字段 1 中有主文档和子文档。子文档的 [parent_id] 等于主文档的 [id]。我如何按 id 和 parent id 对它们进行排序,以便在每个主文档之后都应该是子文档?我知道我应该遍历它,但是有些东西我无法坚持,而且它没有按照我想要的方式排序。

它应该是这样的:

  [0] => Array
    (
    [id] => 111
    [parent_id] => 222
    [field_1] => Main document
    )

  [1] => Array
    (
    [id] => 777
    [parent_id] => 111
    [field_1] => Child document
    )

  [2] => Array
    (
    [id] => 123
    [parent_id] => 222
    [field_1] => Main document
    )

  [3] => Array
    (
    [id] => 789
    [parent_id] => 123
    [field_1] => Child document
    )

  [4] => Array
    (
    [id] => 345
    [parent_id] => 222
    [field_1] => Main document
    )

  [5] => Array
    (
    [id] => 567
    [parent_id] => 345
    [field_1] => Child document
    )

【问题讨论】:

    标签: php arrays sorting multidimensional-array associative


    【解决方案1】:

    基本上,您需要做的是将初始数组分成两部分:主文档数组和子文档数组。然后只需遍历这些数组并组成一个新数组,其中主文档后跟一系列子元素。

    请注意,这是用 php7.4 编写的,我可能使用了一些以前版本的 php 中不可用的语法。

    // extract main documents and sort them by id
    $main_documents = array_filter($input, fn ($document) => $document['field_1'] === 'Main document');
    usort($main_documents, function ($a, $b) {
        return ($a['id'] <=> $b['id']);
    });
    
    // extract child documents and sort them by parent id
    $child_documents = array_filter($input, fn ($document) => $document['field_1'] === 'Child document');
    usort($child_documents, function ($a, $b) {
        return ($a['parent_id'] <=> $b['parent_id']);
    });
    
    $output = [];
    
    // go through each main document and insert it into the output array
    foreach ($main_documents as $main_index => $main_document) {
        $output[] = $main_document;
        // go through all children and see whether they are a child of current main document
        foreach ($child_documents as $child_index => $child_document) {
            // if they are then insert this child after the main element
            if ($main_document['id'] === $child_document['parent_id']) {
                $output[] = $child_document;
                // delete inserted child element from the children array so that next iteration can be faster
                unset($child_documents[$child_index]);
            }
        }
        // delete current main element from the array so that next iteration can be faster
        unset($main_documents[$main_index]);
    }
    

    还有一个更短的版本对初始输入数组进行操作:

    $output = [];
    foreach ($input as $main_index => $document) {
        if ($document['field_1'] === 'Main document') {
            $output[] = $document;
            unset($input[$main_index]);
            foreach ($input as $subloop_index => $subloop_document) {
                if ($document['id'] === $subloop_document['parent_id']) {
                    $output[] = $subloop_document;
                    unset($input[$subloop_index]);
                }
            }
        }
    }
    

    虽然我的回答不是很有效 - 嵌套循环从来都不是一个好习惯,但如果性能不是代码中的问题或效果可以忽略不计,那么我认为应该这样做。

    【讨论】:

    • 我忘了补充“主要文件”的名称不一样。我们必须只使用 id 和 parent id 来比较和排序它们。
    • 如果每个人的主文档的名称都不同,那么您必须添加一些额外的标志来表示文档是否是主文档,并与循环中的比较。像 ['id' => 0, 'parent_id' => 100, 'name' => 'doc', 'is_main' => true]
    • @paperman 如果我的回答对您有帮助,请考虑将其标记为解决方案,谢谢
    猜你喜欢
    • 1970-01-01
    • 2015-04-21
    • 1970-01-01
    • 2016-12-31
    • 2013-02-06
    • 1970-01-01
    • 2019-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多