获取两个数组中存在的相同键值对的数量

时间:2016-03-09 20:56:31

标签: php arrays

我有2个阵列:

$haystack = array(
    array(
        'name' => 'Bill',
        'city' => 'Rome',
        'color' => 'blue'
    ),
    array(
        'name' => 'Jane',
        'city' => 'Wien',
        'color' => 'red'
    )
);

$needles = array(
    array(
        'name' => 'Bill',
        'city' => 'Rome',
        'color' => 'red'
    ),
    array(
        'name' => 'Jane',
        'city' => 'Wien',
        'color' => 'red'
    )
);

现在我想获得$needles$haystack数组中存在(相同)的键值对的数量。结果应该是:

  • 2表示$needles[0]$haystack[0]
  • 0表示$needles[1]$haystack[0]
  • 1代表$needles[0]$haystack[1]
  • 3表示$needles[1]$haystack[1]

我知道,我可以运行丑陋的嵌套foreach

foreach($haystack as $hi => $arr) {
    foreach($arr as $key => $val) {
        foreach($needles as $ni => $needle) {
            if (!isset($matches[$hi][$ni])) {
                $matches[$hi][$ni] = 0;
            }
            foreach($needle as $k => $v) {
                $key == $k && $val == $v && $matches[$hi][$ni]++;
            }
        }
    }
}
print_r($matches);

但还有更好的方法吗?也许我错过了一些内置的数组函数,或者我应该更多地考虑迭代器?

更新:我想补充说,我还有多个针阵列。我用一维数组做了一个简单的例子,但也请考虑一下。

UPDATE2:我在示例中将$needles更改为多维数组。对不起,我从一开始就没有这样做,但我希望用简单的针更容易理解,答案可能会让我知道如何修复多维针......

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

  

现在我想获得$ needle和$ haystack数组中存在的(相同)键值对的数量。

这应符合条例草案:

return array_map(
    function ($straw) use ($needle) {
        return count(array_intersect_assoc($straw, $needle));
    },
    $haystack
);

它会重现一个由吸管组成的干草堆,通过保持相同的键,但每个吸管和参考针之间的公共密钥对的数量值。

  

对于$ haystack [0],结果应为2;对于$ haystack [1],结果应为1。

实际上,根据您的输入数据,它会按预期返回:

Array
(
    [0] => 2
    [1] => 1
)

递归版

在这种情况下,我们有一个带有键的干草堆(和一个针),每个值都可以是一个数组。我们认为两个值是"相等"如果他们相同,除了关键订单。可以通过比较两个阵列的序列化来检查这种相同性;为了实现键顺序不变性,我们不是序列化原始数组,而是使用以确定性方式排序的键(和值的键,递归)进行复制。

function deepmatches($haystack, $needle) {
    // Function to "comb" an array so that all keys are in ascending order.
    $keySort    = function($arr, $ks) {
        if (!is_array($arr)) {
            return $arr;
        }
        ksort($arr, SORT_STRING);
        return array_map(
            function ($values) use ($ks) {
                return $ks($values, $ks);
            },
            $arr
        );
    };

    return array_map(
        function ($straw) use ($needle, $keySort) {
            return count(
                array_uintersect_assoc($straw, $needle,
                    function($val1, $val2) use ($keySort) {
                        if (is_array($val1)) {
                            if (!is_array($val2)) { return -1; }
                            // Both arrays.
                            $val1 = serialize($keySort($val1, $keySort));
                            $val2 = serialize($keySort($val2, $keySort));
                        } else {
                            if (is_array($val2)) { return 1; }
                        }
                        if ($val1 < $val2) { return -1; }
                        if ($val1 > $val2) { return 1; }
                        return 0;
                    }
                )
            );
        },
        $haystack
    );
}

值为字符串时,行为相同。否则,递归地考虑值。

$needle = array(
    'name' => 'Bill',
    'city' => array( 
        'country' => 'Italy', 
        'name' => 'Rome'
    ),
    'color' => 'red'
);

实际案例

这里我们没有递归数组,但数组数组;我们使用针来绘制干草堆:

return array_map(
    function ($straw) use ($needles) {
        // $straw is one Element, $needles is an array of.
        return array_map(
            function ($needle) use ($straw) {
                // How many elements are common between $needle and $straw
                return count(array_intersect_assoc($straw, $needle));
            },
            $needles
        );
    },
    $haystack
);

这将返回一个与$ haystack基数相同的数组,其中包含具有相同基数$ needle的数组。所以

$ret[5][2]

包含haystack的第六个元素和第三个针之间有多少个共同元素。

鉴于主要的时间花费在intersect_assoc中,很可能foreach()结构会变得更快。闭包需要扭曲范围并运用堆栈,而foreachs不要:

$ret = [ ];
foreach ($haystack as $kh => $straw) {
    $row = [ ];
    foreach ($needles as $kn => $needle) {
        $row[$kn] = count(array_intersect_assoc($straw, $needle));
    }
    $ret[$kh] = $row;
}
unset($row);

答案 1 :(得分:1)

计算array_intersect_assoc的结果应该会略微简化代码。

foreach ($haystack as $i => $arr) {
    $matches = count(array_intersect_assoc($needle, $arr));
    echo "Needle found {$matches} times in haystack at index {$i} \n";
}