使用阈值/容差比较具有匹配键的两个数组中的数字值

5

我需要将数据库的值与提交的数值进行比较。如果提交的数值(十进制价格)在2美分阈值内,则认为值相等。结果是一个包含“真实”差异的数组。数组是一致的:具有相同数量的值和相同的键。

$db_values =   array( "21" => 10.00, "22" => 20.00, "25" => 3.55);
$post_values = array( "21" => 9.98,  "22" => 20.01, "25" => 2.55 ); 

我正在尝试将绝对值与我的容差值(epsilon)进行比较,使用方法是array_udiff(PHP中比较小数):

function epsilon_compare ($v1,$v2)
{
 $epsilon = 0.02;
 $diff = abs($v1 - $v2);

   if ($diff <= $epsilon) 
    { 
            return 0;
      //echo "numbers are equal";
      } else {
         return 1;
             }
    }

 print_r(array_udiff($post_values, $db_values, "epsilon_compare"));

给出正确结果:数组([25] => 2.55)

但是当我使用不同的数组时,结果会出错,例如:

   $db_values =   array( "21" => 10.00, "22" => 20.00, "25" => 3.55);
   $post_values = array( "21" => 8.00,  "22" => 20.01, "25" => 2.55 );

在这种情况下,它给出:
   Array ( [21] => 8 [22] => 20.01 [25] => 2.55 ) 

列表中列出了键 [22] => 20.01,但它在阈值范围内,因此不应该在结果集中。我认为我没有完全理解array_udiff方法。谢谢。


如果您将传递给array_udif的数组顺序颠倒(即使用($db_values, $post_values, "epsilon_compare")调用它),会发生什么?如果您得到不同的结果,这可能表明"epsilon_compare"出了一些问题。 - imm
首先,比较函数不应该返回布尔值。应该返回“小于零”,“等于零”或“大于零”的整数。 - poop-deck
2个回答

1

我不认为 udiff 做的是你想要的功能。如果你打印 v1 和 v2,它将给出以下结果:

v1: 20.01 v2: 9.98
v1: 2.55 v2: 20.01
v1: 20 v2: 10
v1: 3.55 v2: 20
v1: 9.98 v2: 10
v1: 9.98 v2: 20.01
v1: 20.01 v2: 20
v1: 20.01 v2: 2.55
v1: 2.55 v2: 3.55 

它进行的比较比你想象的要多。

你可能需要一段类似于以下代码的代码:

function compare_arrays($array1, $array2){
    $result = array();
    foreach($array1 as $value => $outcome){
        if(epsilon_compare($array1[$value], $array2[$value])){
            $result[$value] = $array2[$value];
        }
    }
    return $result;
}

当使用我的“epsilon_compare”函数时,它会出现错误(未定义的偏移量)。 - phpJs
当测试VolkerK的解决方案时,我得到了不一致的结果。如果您能帮助我使其正常工作,那么这可能是正确的方法。 - phpJs
我已经纠正了关联数组的结果。如果您的数组中有多个重复的关联,请添加以下内容:if(isset($result[$value])) array_push($result[$value],$array2[$value]); - Dennis
这是正确的答案,不应使用VolkerK的答案。array_udiff()没有尊重关联两个数组元素的键。array_udiff_assoc()将从自定义回调函数发出DEPRECATED通知,因为布尔返回值。对于此任务,使用_diff函数没有任何好处。这个答案是我百分之百会这样做的。 - mickmackusa

-1

http://docs.php.net/array_udiff

用户提供的回调函数用于比较。如果第一个参数被认为小于、等于或大于第二个参数,则它必须返回一个整数小于、等于或大于零。
如果元素不相等,您的函数始终返回1,这会导致不同(错误)的比较决策。

<?php
function epsilon_compare ($v1,$v2)
{
    $epsilon = 0.02;
    $diff = $v1 - $v2;
    return abs($diff)<=$epsilon ? 0 : $diff;
}

$db_values =   array( "21" => 10.00, "22" => 20.00, "25" => 3.55);
$post_values = array( "21" => 8.00,  "22" => 20.01, "25" => 2.55 );
print_r(array_udiff($post_values, $db_values, "epsilon_compare"));

打印

Array
(
    [21] => 8
    [25] => 2.55
)

编辑:使用array_udiff_assoc

$db_values = array ( "1" => 7.55, "2" => 5.45, "3" => 5.45, "4" => 64.45, "5" => 54.75, "6" => 30.40, "7" => 56.99, "8" => 10.90, "9" => 60.85, "11" => 3.25, "12" => 13.05, "13" => 5.45, "14" => 8.00, "15" => 5.45, "16" => 13.05, "17" => 4.35 );
$post_values = array ( "1" => 7.55, "2" => 5.45, "3" => 5.45, "4" => 64.45, "5" => 54.75, "6" => 30.40, "7" => 56.99, "8" => 10.90, "9" => 60.85, "11" => 3.25, "12" => 13.05, "13" => 2.45, "14" => 8.00, "15" => 5.45, "16" => 12.05, "17" => 2.34 );
print_r(array_udiff_assoc($post_values, $db_values, "epsilon_compare"));

打印

Array
(
    [13] => 2.45
    [16] => 12.05
    [17] => 2.34
)

你对Dennis的评论“udiff”在这种情况下进行了更多比较,有何看法? - phpJs
$db_values = array("1" => 7.55, "2" => 5.45, "3" => 5.45, "4" => 64.45, "5" => 54.75, "6" => 30.40, "7" => 56.99, "8" => 10.90, "9" => 60.85, "11" => 3.25, "12" => 13.05, "13" => 5.45, "14" => 8.00, "15" => 5.45, "16" => 13.05, "17" => 4.35); $post_values = array("1" => 7.55, "2" => 5.45, "3" => 5.45, "4" => 64.45, "5" => 54.75, "6" => 30.40, "7" => 56.99, "8" => 10.90, "9" => 60.85, "11" => 3.25, "12" => 13.05, "13" => 2.45, "14" => 8.00, "15" => 5.45, "16" => 12.05, "17" => 2.34); 如果您使用上述两个数组,则结果不正确(只有16=>12.05)。 - phpJs
这就是array_udiff的工作原理。返回一个包含array1中所有不在其他参数中出现的值的数组。如果想要其他结果,您需要指定/解释规则... - VolkerK
我需要按键比较数组值。因此,需要将第一个数组中键“17”的值与第二个数组中键“17”的值进行比较,而不是其他任何值。 也许在这种情况下使用foreach循环会更好。 - phpJs
到目前为止,我已经测试了udiff_assoc的正常工作。我将这行代码进行了更改:return abs($diff)<=$epsilon ? 0 : 1; 将$diff改为了1。应该没问题吧(?) - phpJs
array_udiff()没有尊重与两个数组元素相关的键。array_udiff_assoc()将从自定义回调函数发出DEPRECATED通知,因为它返回布尔值。使用_diff函数对于此任务没有任何好处。同时比较每个相关元素的基本循环是正确的解决方案。 - mickmackusa

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