我有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
数组中存在(相同)的键值对的数量。结果应该是:
$needles[0]
和$haystack[0]
$needles[1]
和$haystack[0]
$needles[0]
和$haystack[1]
$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
更改为多维数组。对不起,我从一开始就没有这样做,但我希望用简单的针更容易理解,答案可能会让我知道如何修复多维针......
感谢您的帮助!
答案 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";
}