如何在多维关联数组上递归实现 array_intersect_assoc()

问题描述 投票:0回答:4

假设我想这样做:

$a = array_intersect_assoc(
 array(
  'key1' => array(
   'key2' => 'value2'
  ),
  'key3' => 'value3',
  'key4' => 'value4'
 ),
 
 array(
  'key1' => array(
   'key2' => 'some value not in the first parameter'
  ),
  'key3' => 'another value'
 )
);

var_dump( $a );

打印结果为:

数组
  '键1'=> 
    大批
      'key2' => 字符串'value2'(长度=6)

很明显,两个数组中与“key2”关联的值并不相同,但是

array_intersect_assoc()
仍然返回
'key2' => 'value2'
作为相交值。

这是

array_intersect_assoc()
的预期行为吗?

谢谢!

php arrays multidimensional-array filter associative-array
4个回答
10
投票

是的,这是预期的行为,因为比较是使用字符串表示形式完成的,并且该函数不会向下递归嵌套数组。来自手册

仅当 (string) $elem1 === (string) $elem2 时,key => value 对中的两个值才被视为相等。换句话说,执行严格的类型检查,因此字符串表示形式必须相同。

如果您尝试使用

'key1' => 'Array'
与数组相交,您会得到相同的结果,因为数组的字符串表示形式始终是
'Array'

nleippe 的用户贡献的注释之一包含一个看起来很有前途的递归实现(我修改了第三行以对任何非数组值进行字符串比较):

function array_intersect_assoc_recursive(&$arr1, &$arr2) {
    if (!is_array($arr1) || !is_array($arr2)) {
//      return $arr1 == $arr2; // Original line
        return (string) $arr1 == (string) $arr2;
    }
    $commonkeys = array_intersect(array_keys($arr1), array_keys($arr2));
    $ret = array();
    foreach ($commonkeys as $key) {
        $ret[$key] =& array_intersect_assoc_recursive($arr1[$key], $arr2[$key]);
    }
    return $ret;
}

2
投票

满足您需要的功能:

/**
 * Get array intersect assoc recursive.
 *
 * @param mixed $value1
 * @param mixed $value2
 *
 * @return array|bool
 */
function getArrayIntersectAssocRecursive(&$value1, &$value2)
{
    if (!is_array($value1) || !is_array($value2)) {
        return $value1 === $value2;
    }

    $intersectKeys = array_intersect(array_keys($value1), array_keys($value2));

    $intersectValues = [];
    foreach ($intersectKeys as $key) {
        if (getArrayIntersectAssocRecursive($value1[$key], $value2[$key])) {
            $intersectValues[$key] = $value1[$key];
        }
    }

    return $intersectValues;
}

1
投票
function array_key_match_recursive(array $main, array $other, $i = 0, &$result = []) {
    foreach($main as $key => $value) {
        $k = sprintf('%s%s', str_repeat('=', $i), $key);
        if (!isset($other[$key])) {
            $result[$k][] = 'not key';
        }
        if (!is_array($value) && empty($other[$key])) {
            $result[$k][] = 'value empty';
        }
        if (is_array($value) && isset($other[$key])) {
            array_key_match_recursive($value, $other[$key], ++$i, $result);
        }
    }

    //return (bool) !$result;
    return $result;
}

-1
投票

我的版本基于@BoltClock版本:

function array_intersect_assoc_recursive($arr1, $arr2) {
    if (!is_array($arr1) || !is_array($arr2)) {
        return $arr1;
    }
    $commonkeys = array_keys($arr1);
    if (!array_key_exists('$', $arr2)){
        $commonkeys = array_intersect(array_keys($arr1), array_keys($arr2));
    }
    $ret = array();
    foreach ($commonkeys as $key) {
        $ret[$key] = array_intersect_assoc_recursive($arr1[$key], array_key_exists('$', $arr2) ? $arr2['$'] : $arr2[$key]);
    }
    return $ret;
}

我使用此代码来过滤复杂数组内的数据

示例:

$filter = [
    'channels' => [
        '$' => [
            'id' => 1,
            'type' => 1,
            'count' => 1
        ]
    ],
    'user' => [
        'id' => 1,
        'type' => 1
    ]
];
$data = [
    'user' => [
        'id' => '1234',
        'type' => true,
        'counter' => 14,
    ],
    'filteredField' => 4,
    'channels' => [
        ['id' => '567', 'type' => 'other', 'count' => 1345, 'filteredField' => 5,],
        ['id' => '890', 'type' => 'other', 'count' => 5456, 'filteredField' => 7,],
    ],
];
print_r(array_intersect_assoc_recursive($data, $filter));

在线测试: https://onlinephp.io/c/3be04

© www.soinside.com 2019 - 2024. All rights reserved.