PHP减去数组值

9
我有一个包含键和值的数组。每个值都是整数。我有另一个具有相同键的数组。如何减去所有匹配键的值?同时,第二个数组中可能存在未出现在第一个数组中的键。如果数组2中存在未出现在数组1中的键,则其值应保持不变。如果第一个数组中存在未在第二个数组中的键,则应将其舍弃。怎么做呢?是否有任何内置函数可以实现此功能?
如果我要编写脚本,它会类似于以下的for循环:
$arr1 = array('a' => 1, 'b' => 3, 'c' => 10);
$arr2 = array('a' => 2, 'b' => 1, 'c' => 5);
$ret = array();
foreach ($arr1 as $key => $value) {
    $ret[$key] = $arr2[$key] - $arr1[$key];
}
print_r($ret);
/*
should be: array('a' => 1, 'b' => -2, 'c' => -5)
*/

我没有在这里添加一个情况,那就是一个关键字在一个数组中而不在另一个数组中。

3
你走在正确的路上……我认为只要再加一点努力,你就能实现自己的目标。 - Aurelio De Rosa
3个回答

24

如果你愿意的话,你可以使用数组函数来避免使用foreach。

下面提供给array_mapdocs的闭包将从每个对应的$arr2中减去每个$arr1的值。不幸的是,当使用多个输入数组时,array_map不会保留你的键,所以我们使用array_combinedocs将减去的结果与原始键合并回一个数组中:

$arr1 = array('a' => 1, 'b' => 3, 'c' => 10);
$arr2 = array('a' => 2, 'b' => 1, 'c' => 5);

$subtracted = array_map(function ($x, $y) { return $y-$x; } , $arr1, $arr2);
$result     = array_combine(array_keys($arr1), $subtracted);

var_dump($result);

更新

我对数组函数的使用方法与简单的foreach循环进行了比较,并使用Xdebug对两者进行了基准测试。以下是测试代码:

$arr1 = array('a' => 1, 'b' => 3, 'c' => 10);
$arr2 = array('a' => 2, 'b' => 1, 'c' => 5);

function arrayFunc($arr1, $arr2) {
  $subtracted = array_map(function ($x, $y) { return $y-$x; } , $arr1, $arr2);
  $result     = array_combine(array_keys($arr1), $subtracted);
}

function foreachFunc($arr1, $arr2) {
  $ret = array();
  foreach ($arr1 as $key => $value) {
    $ret[$key] = $arr2[$key] - $arr1[$key];
  }
}

for ($i=0;$i<10000;$i++) { arrayFunc($arr1, $arr2); }
for ($i=0;$i<10000;$i++) { foreachFunc($arr1, $arr2); }

事实证明,使用foreach循环比使用数组函数完成相同任务要快上一个数量级。从下面的KCachegrind被调用者图像中可以看出,数组函数方法在上述代码中所需的处理时间几乎占据了80%,而foreach函数只需要不到5%。

enter image description here

这里的教训是:有时候在PHP中,更语义化的数组函数(令人惊讶地)在性能上可能不如一个传统的循环。当然,你应该始终选择更可读/语义化的选项;如果这样的微优化使得代码在六个月后更难理解,那么这样的优化是不合理的。

请注意,我在此测试中使用了PHP 5.4RC6和一个AMD64 2.2Ghz的CPU。 - user895378
还有一件事:我运行了测试多次,并在每个连续的迭代中获得了类似的结果。 - user895378
此外,您还需要添加一些额外的代码来检查$arr$arr2中的键是否匹配,如问题中所述 - 使用foreach可以更轻松地完成这项工作。 - Izkata
@Izkata -- 只有在键不是以相同的顺序开始时(它们在 OP 中是这样的)-- PHP 中的关联数组是有序的,因此您不必担心键会跳来跳去。 - user895378
我指的是“也许有一些键在第二个数组中不存在,但两个数组的长度相同。”,例如$arr2具有键d而不是c - Izkata

1
foreach ($arr2 as $key => $value) {
    if(array_key_exists($key, $arr1) && array_key_exists($key, $arr2))
        $ret[$key] = $arr2[$key] - $arr1[$key];
}

嗯... array_key_exists($key, $arr2) 会一直是 true... 因为这就是你正在迭代的内容。 - undefined

0

PHP不提供向量化的数学运算。我建议您继续使用循环的方法。

首先,我会获取每个数组的键集合(请参阅array_keys函数)。然后,取交集。现在你将拥有每个数组共同的键。(看一下array_intersect函数)。最后,进行迭代。这是一种可读性强且简单的方法。

最后,您可以查看一些库,例如Math_Vector:http://pear.php.net/package/Math_Vector


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接