【问题标题】:Combine Two Multidimensional Arrays in PHP With The Same ID在 PHP 中合并两个具有相同 ID 的多维数组
【发布时间】:2018-10-30 10:40:15
【问题描述】:

我想将一个数组中的值添加到另一个数组中,当它们具有相同的 ID 时,它们都可能是多维的。很难解释,所以我添加了示例。

arr1 => 新结构,没有完整数据

arr2 => 旧结构,包含完整数据

如果您愿意提供帮助,请举例:

// arr1 (the correct structure/order, without the full data)
[{
    "id": "24",
    "children": [{
        "id": "21",
        "children": [{
            "id": "15"
        }]
    }]
}]



// arr2 (full data, not in any specific order, may be nested)
[{
    "id": "24",
    "name": " x",
    "time": "0",
    "status": "0"
}, {
    "id": "21",
    "children": [{
        "id": "15",
        "name": "x",
        "time": "0",
        "status": "0"
    }],
    "name": "x",
    "time": "0",
    "status": "0"
}]


// arr3 (desired output for this example)
[{
    "id": "24",
    "children": [{
        "id": "21",
        "children": [{
            "id": "15",
            "name": "x",
            "time": "0",
            "status": "0"
        }],
        "name": "x",
        "time": "0",
        "status": "0"
    }],
    "name": " x",
    "time": "0",
    "status": "0"
}]

我试过这个:

    function merge($arr1, $arr2) {
        foreach($arr1 as $key => $value){
            foreach($arr2 as $value2) {
                if($value['id'] === $value2['id']){
                    $arr1[$key]['name'] = $value2['name'];
                    $arr1[$key]['time'] = $value2['time'];
                    $arr1[$key]['status'] = $value2['status'];
                    if (is_array($value)) {
                        $arr1[$key]['children'] = merge($arr1, $arr2);
                    }
                }

            }
        }
        return $arr1;
    }

组合它们,但我不知道如何正确处理嵌套。我已经尝试了很多其他的东西,比如使用 array_merge_recursive() 但它不起作用,因为我想根据 ID 值进行合并。任何能让我走上正轨的帮助都会非常感谢。

当前输出举例:

[{
    "id": "24",
    "children": [{
        "id": "21",
        "children": [{
            "id": "15"
        }]
    }],
    "name": " x",
    "time": "0",
    "status": "0"
}]

所需的输出例如:

[{
    "id": "24",
    "children": [{
        "id": "21",
        "children": [{
            "id": "15",
            "name": "x",
            "time": "0",
            "status": "0"
        }],
        "name": "x",
        "time": "0",
        "status": "0"
    }],
    "name": " x",
    "time": "0",
    "status": "0"
}]

【问题讨论】:

  • 现在出了什么问题?你还能显示当前输出吗?
  • 那些 json 字符串无效,顺便说一句。
  • 嘿@Jeff 我添加了更小的工作!我想澄清一下,结构不准确,可能有 20 层深,也可能是 1 层,谢谢!
  • @Jeff 我还为工作的 json 数据添加了当前输出示例。它正确复制不在子数组中的任何内容,但不适用于任何内部数组。
  • 从你的例子中我开始更好地理解 - 你希望来自 arr2 的 ID 为“21”的人成为“24”的孩子,对吧?

标签: php arrays


【解决方案1】:

编辑 - 我想我现在明白了这个问题

从您给出的示例中,我意识到了问题 - 您的旧数组包含所有数据,但没有父子关系,因此您想用旧数组中的数据填充新数组(具有正确的关系)大批。这里的问题是合并函数必须从旧数组中的任意一代获取数据以填充新数组。这可能意味着很多循环。

所以我认为解决方案是首先遍历旧数据并将其展平 - 只需有一个关联数组,其中键是“id”值。然后遍历新数组并从扁平的“查找”数组中填充它。那有意义吗?无论如何,您将拥有两个功能:

$lookUp = array();

//recursive function to flatten $arr2 into $lookUp array.
function indexOriginal($arr, &$lookUp) {
    foreach($arr as $value) {
        $lookUp[$value["id"]] = $value;
        if (isset($value['children'])) {
            unset($lookUp[$value["id"]]['children']);
            indexOriginal($value['children'], $lookUp);
        }
    }
}
indexOriginal($arr2, $lookUp);

然后你填充新数组:

function fillInNew($arr, $lookUp) {
    $return = array();
    foreach($arr as $value) {
        $newEntry = $lookUp[$value["id"]];
        if (isset($value['children'])) $newEntry['children'] = fillInNew($value['children'], $lookUp);
        $return[] = $newEntry;
    }
    return $return;
}
$newArr = fillInNew($arr1, $lookUp);

$newArr 应该是你要找的东西

以前的旧无用的东西:

你的这部分代码对我来说很奇怪:

if (is_array($value)) {
    $arr1[$key]['children'] = merge($arr1, $arr2);
}

显然我可能完全糊涂了,但你不只需要把这个吗?

if (isset($value2['children'])) $arr1[$key]['children'] = array_merge($arr1[$key]['children'], $value2['children']);

编辑:我添加了array_merge,因为我看到不完整版本中的“子”数组也可能需要合并。

编辑 2:现在我注意到孩子可以有更多的孩子(我猜是有道理的),这就是为什么你有递归使用函数的正确想法。您似乎传入了错误的数组 - 您想传入 $arr1[$key]['children'] (作为不完整的数组)和 $value2['children'] (作为完整的数组)

function merge($arr1, $arr2) {
    foreach($arr1 as $key => $value){
        foreach($arr2 as $value2) {
            if($value['id'] === $value2['id']){
                $arr1[$key]['name'] = $value2['name'];
                $arr1[$key]['time'] = $value2['time'];
                $arr1[$key]['status'] = $value2['status'];
                if (isset($value2['children'])) $arr1[$key]['children'] = merge($arr1[$key]['children'], $value2['children']);
            }

        }
    }
    return $arr1;
}

【讨论】:

  • 对,但这只会复制孩子,因为孩子可能在 array1 中,但不在 array2 中,反之亦然,这不适用于除顶部之外的级别。
  • 刚刚发现并编辑了该行。我认为您的初始代码的问题是 if (is_array($value)) 行,它仅检查 arr1,这可能不完整,对吗?检查 $value2 似乎更有意义
  • 这不会从第一个级别之后的级别复制任何数据(名称、时间、状态)。
  • 你看到第二个编辑了吗?另外,我是否理解只有当 id(子或父)出现在 arr1 时才应填充数据,但如果它只出现在 arr2 中则忽略?如果是,那么条件应该是:if (is_array($arr1[$key]['children']))
  • 永远不会出现ID只出现在一个数组中的情况,但是如果它只出现在数据数组中,那么我猜应该忽略它。我确实看到了编辑,但它不像我说的那样工作。如果您想对其进行测试,我通过工作示例和输出向 OP 添加了更多信息,非常感谢您的帮助!
【解决方案2】:

编辑:这个怎么样?

$detailsClean = [];

foreach($array2 as $item) {
    $detailsClean = removeDepth($item, $detailsClean);
}


foreach($array1 as $itemKey => $item) {
    $array1[$itemKey] = addDetails($item, $detailsClean);
}


function removeDepth($array, $result) {
    $id = $array['id'];
    if (!empty($array['children'])) {
        foreach($array['children'] as $child) {
            $result = removeDepth($child, $result);
        }
        unset($array['children']);
    }
    $result[$id] = $array;

    return $result;
}

function addDetails($array, $details) {
    $id = $array['id'];
    if (isset($details[$id])) {
        $array = array_merge($array, $details[$id]);
        if (!empty($array['children'])) {
            foreach($array['children'] as $childKey => $child) {
                $array['children'][$childKey] = addDetails($child, $details);
            }
        }
    }
    return $array;
}

$array1 用最终结果更新。

以下是您未编辑帖子中数据的示例:http://phpio.net/s/7z09

【讨论】:

  • 是的,孩子可以有孩子,也可以有孩子,等等。这就是为什么我确信这里需要递归。您的解决方案只返回一个带有 arr1 的单个数组的结果,然后将 arr2 附加到末尾。
  • @JacobSussan 添加了一个新示例,该示例首先从所有细节(array2)中删除深度,然后循环通过 array1 以添加此细节。
  • 谢谢你是一个活生生的救星,整天都在努力解决这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-30
  • 2014-03-04
相关资源
最近更新 更多