【问题标题】:Why does array_uintersect_assoc() need the comparison function to return non-boolean values?为什么 array_uintersect_assoc() 需要比较函数返回非布尔值?
【发布时间】:2017-04-05 11:03:39
【问题描述】:

不知道为什么array_uintersect_assoc()的自定义比较功能:

如果第一个参数被认为分别小于、等于或大于第二个参数,则必须返回一个小于、等于或大于零的整数

当我比较两个数组时,我只需要一个布尔返回值:元素要么匹配,要么不匹配。

这种行为的真正原因是什么?

【问题讨论】:

    标签: php arrays comparison intersection custom-function


    【解决方案1】:

    该函数以这种方式实现,以允许使用使用这种返回策略的“经典”比较函数。出于显而易见的原因,这样的函数通常需要能够表达 三种 种情况,而这对于布尔返回值是不可能的。

    但是,您也可以使用比较函数,该函数确实返回布尔结果,因为 php 作为弱类型语言会自动为您转换。看一下这个示例,它是函数文档中给出的示例的略微修改版本:

    <?php
    function mystrcasecmp($a, $b) {
        return strcasecmp($a, $b) ? true : false;
    }
    
    $array1 = array("a" => "green", "b" => "brown", "c" => "blue", "red");
    $array2 = array("a" => "GREEN", "B" => "brown", "yellow", "red");
    
    print_r(array_uintersect_assoc($array1, $array2, "mystrcasecmp"));
    

    您可以看到这里使用的比较函数返回一个布尔值,但结果完全相同。

    底线:现有实现更加灵活,同时允许使用返回布尔结果的比较函数。

    【讨论】:

      【解决方案2】:

      我只需要布尔值:元素要么匹配要么不匹配。

      TL;DR

      您需要反转将转换为 int 的布尔值,因为这些调用自定义函数的 array_intersectarray_diff 函数仅限定返回零结果的数据(即:null、@987654326 @、"0"0、空字符串、空数组)。这是一个三元实现:

      array_uintersect_assoc($array1, $array2, fn($a, $b) => str_contains($a, $b) ? 0 : 1)
      

      解释...

      这个操作很容易混淆。你的问题让我发帖Unexpected results with array_uintersect_assoc() when callback returns non-numeric string

      假设您想使用array_uintersect_assoc(),并且您有以下两个输入数组:

      $array1 = ["a" => "green", "b" => "brown", "c" => "blue", 0 => "red"];
      $array2 = ["a" => "GREEN", "B" => "brown", 0 => "yellow", 1 => "red", "c" => "blue"];
      

      现在假设您要进行一个返回布尔值的自定义函数调用。我将提名 PHP8 的 str_contains(),这对于这个演示来说已经足够了。第一个数组将包含干草堆字符串,第二个数组将包含针字符串。

      var_export(array_uintersect_assoc($array1, $array2, 'str_contains'));
      

      这将检查第二个数组中第一个数组中的相同键然后在那些合格元素中,它将检查第二个数组的值是否在第一个数组的字符串中找到。作为一个“相交”调用,您会直观地期望:

      ['c' => 'blue']
      

      因为只有第二个数组中的c-keyed 元素具有一个值,其中第二个数组的值区分大小写存在于第一个数组的值中。

      但是,您实际上得到的是:

      ['a' => 'green', 0 => 'red']
      

      什么?!?您在结果中获得带有键 a0 的元素的原因是,当 0 结果为返回。

      c 元素的值被馈送到str_contain() 时,会返回一个true 布尔值。 array_uintersect_assoc() 然后强制将布尔值转换为 int 类型。将布尔值转换为整数时,false 变为 0true 变为 1

      要修复此行为以获得预期结果,您不能简单地将函数名称中的 intersect 单词更改为 diff - 这会创建:

       ['b' => 'brown', 'c' => 'blue']
      

      这是因为b 在第二个数组中没有相同的对应键。 c 确实有一个相同的对应键,str_contains()true 结果被 array_udiff_assoc() 评估为“不要保留”。

      最后,解决方法是反转布尔值,使true 变为0false 变为非零。 (Demo)

      var_export(
          array_udiff_assoc(
              $array1,
              $array2,
              fn($a, $b) => str_contains($a, $b) ? 0 : 1;
              // or         !str_contains($a, $b)  until the day when PHP throws a DEPRECATED warning for returning a boolean
          )
      );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-08
        • 1970-01-01
        • 2013-02-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-11
        • 1970-01-01
        相关资源
        最近更新 更多