【问题标题】:Fastest return TRUE if all values of a column of a multidimensional array is_numeric如果多维数组的一列的所有值都是_numeric,则最快返回 TRUE
【发布时间】:2019-01-21 22:17:43
【问题描述】:

是否有更快的方法来检查一个数字(不是null)的存在 php 中多维数组的列(例如,number9)?

尝试:

下面的if statement 似乎工作正常。

$arr=Array(
    [0] => Array
        (
            [date] => 2019-01-16
            [number1] => 20.4
            [number2] => 20.54
            [number3] => 19.71
            [number4] => 19.73
            [number5] => 70849266
            [number6] => 70849266
            [number7] => -0.65
            [number8] => -3.189
            [number9] => 20.0902
            [string1] => Jan 16
            [number10] => 0.047796070100903
        )

    .
    .
    .

    [21] => Array
        (
            [date] => 2019-01-17
            [number1 => 19.49
            [number2] => 20.51
            [number3] => 19.02
            [number4] => 20.25
            [number5] => 85018421
            [number6] => 85018421
            [number7] => 0.52
            [number8] => 2.636
            [number9] => 19.7988
            [string1] => Jan 17
            [number10] => 0.075411577270313
        )

);


function isNumeric($var){
  if (is_numeric($var)){
    return true;
  } else {
    return false;
  }
}


if((array_walk(array_column($arr, "number8"), 'isNumeric'))!=1)

【问题讨论】:

  • 你为什么不在array_walk中直接使用is_numeric
  • 在大多数情况下,使用 foreach 迭代数组将比 array_walk 执行得更快。
  • @Dharman array_walk() 中的回调需要带两个参数。
  • The if statement below seems to be working okay 给定您提出的代码,我怀疑,但是如果您拼写相同,则isNumericisNumberic 可能会发生实际情况。当然,尽管))!=1 不确定应该做什么,但您仍然会遇到此问题,但这是不正确的。您可能认为它有效,但 array walk always Returns TRUE. php.net/manual/en/function.array-walk.php (根据文档)

标签: php arrays multidimensional-array null numbers


【解决方案1】:

感谢大家,感谢您的精彩回答!

在我的 PC 上,我在 PHP 5.5.38 中尝试了您的四个函数,迭代次数约为 5000 次,总时间为:

"is_numeric_array_with_cast total time is 0.44153618812561"
"with_array_filter total time is 0.21628260612488"
"is_numeric_array_with_func total time is 0.14269280433655"
"is_numeric_matt_fryer total time is 0.155033826828"


$t1=$t2=$t3=$t4=0;
foreach($arrs as $k=>$arr){
    $s1=microtime(true);
    is_numeric_array_with_cast(array_column($arr, "number8"));
    $e1=microtime(true)-$s1;
    $t1=$t1+$e1;

    $s2=microtime(true);
    with_array_filter(array_column($arr, "number8"));
    $e2=microtime(true)-$s2;
    $t2=$t2+$e2;


    $s3=microtime(true);
    is_numeric_array_with_func(array_column($arr, "number8"));
    $e3=microtime(true)-$s3;
    $t3=$t3+$e3;

    $s4=microtime(true);
    is_numeric_matt_fryer(array_column($arr, "number8"),"number8");
    $e4=microtime(true)-$s4;
    $t4=$t4+$e4;

}






function is_numeric_array_with_cast($arr) {
    foreach ($arr as $b) {
        if ($b != (string)(float)$b) {
            return false;
        }
    }
    return true;
}


function with_array_filter($arr) {
    return $arr == array_filter($arr, 'is_numeric');
}


function is_numeric_array_with_func($arr) {
    foreach ($arr as $b) {
        if (!is_numeric($b)) {
            return false;
        }
    }
    return true;
}

function is_numeric_matt_fryer($arr,$str){
  $bool = true;
  foreach ($arr as $row)
  {
      if (!is_numeric($row[$str]))
      {
          $bool = false;
      }
  }
  return $bool;
}

【讨论】:

    【解决方案2】:

    这是我的想法。
    首先是仅过滤数组中的数字值并与原始值进行比较:

    function with_array_filter($arr) {
        return $arr == array_filter($arr, 'is_numeric');
    }
    

    第二个示例使用转换为浮点数,然后再转换为字符串,请记住,对于非常大的数字,这并不准确,但似乎是最快的(如果您完全关心的话):

    function is_numeric_array_with_cast($arr) {
        foreach ($arr as $b) {
            if ($b != (string)(float)$b) {
                return false;
            }
        }
        return true;
    }
    

    然而,最简单的解决方案可能是只在函数内 foreach 数组并提前返回:

    function is_numeric_array_with_func($arr) {
        foreach ($arr as $b) {
            if (!is_numeric($b)) {
                return false;
            }
        }
        return true;
    }
    

    在 PHP 7.2 上以超过 100000 次迭代的 20 个元素的数组为基准:

    $falseArray = [
        '1',
        2.5,
        -10,
        32,
        11.0,
        2.5,
        100101221,
        345,
        -10,
        '-10',
        '+10',
        '10',
        12,
        PHP_INT_MAX,
        PHP_INT_MAX + 1.4e5,
        '-10',
        null,
        'a',
        '5',
        5
    ];
    
    Matt Fryer
    Time: 4.8473789691925
    
    is_numeric_array_with_func
    Time:  4.0416791439056
    
    is_numeric_array_with_cast
    Time:  3.2953300476074
    
    with_array_filter
    Time:  3.99729180336
    

    【讨论】:

      【解决方案3】:

      正如我在 cmets 中所说的:

      下面的 if 语句似乎工作正常

      但是,鉴于您提出的代码,我对此表示怀疑:让我们看看吧。

      function isNumeric($var){ ... }
      
      if(array_walk(array_column($arr, "number8"), 'isNumberic'))!=1
      

      首先也是最明显的就是这 2 个

      • isNumberic vs isNumeric,这是一个致命的未定义函数错误(拼写/错字)。
      • )!=1 那么这超出了实际情况,或者换一种说法if(...){ !=1 }

      让我们假设这些只是问题中的拼写错误。即使您的代码没有我上面提到的 2 个“缺陷”,您仍然会遇到这个问题,array_walk 通过引用工作并简单地返回 true(总是)。通过引用传递更新“原始”变量而不返回它的副本(在 array_walk 的情况下)

      http://php.net/manual/en/function.array-walk.php

      返回值 返回 TRUE。

      这当然会让你的病情无论如何都通过。因此,您应该始终测试条件的通过和失败(就像我在其中放置一些“罐装”坏数据所做的那样)。这样我就可以 100% 确切地知道我的代码的行为方式。

      其他人已经发布了如何纠正这个问题,但没有发布你做错了什么。但为了完整起见,无论如何我都会发布答案。

      $arr = array (
          0 => 
          array (
              'date' => '2019-01-16',
              'number1' => 20.4, 
              'number2' => 20.54,
              'number3' => 19.71,
              'number4' => 19.73,
              'number5' => 70849266,
              'number6' => 70849266,
              'number7' => -0.65,
              'number8' => -3.189,
              'number9' => 20.0902,
              'string1' => 'Jan16',
              'number10' => 0.047796070100903
          ),
          array (
              'date' => '2019-01-16',
              'number1' => 20.4, 
              'number2' => 20.54,
              'number3' => 19.71,
              'number4' => 19.73,
              'number5' => 70849266,
              'number6' => 70849266,
              'number7' => -0.65,
              'number8' => 'foo',#intentially not number
              'number9' => 20.0902,
              'string1' => 'Jan16',
              'number10' => 0.047796070100903
          ),
      
      );
      
      $col = array_column($arr, "number8");
      $col1 = array_filter($col, 'is_numeric');
      
      if($col != $col1){
          echo "not the same\n";
      }
      

      输出:

      not the same
      

      Sandbox

      我应该提到,没有“需要”计算这些,因为 PHP 可以比较复杂对象的相等性。当我们在(可能)删除一些元素之后将相同的“根”数组(在本例中为$col)与自身进行比较时,如果没有删除任何元素,那么两个数组不仅应该是相同的长度,而且应该是“相同的”。

      此外,如果您想在一行中(在条件内)执行此操作,您可以这样做:

      if( ($col = array_column($arr, "number8")) && $col != array_filter($col, 'is_numeric')){
          echo "not the same\n";
      }
      

      阅读难度有点大,注意$col = array_column赋值。

      【讨论】:

        【解决方案4】:

        使用foreach 循环:

        $bool = true;
        foreach ($arr as $row)
        {
            if (!is_numeric($row['number8']))
            {
                $bool = false;
                break;
            }
        }
        

        【讨论】:

        • 如果可能,请在此处发布您的结果,这会很有趣:)
        • if (!$bool = $bool && is_numeric($row['number8'])) break; 可能效率更高...
        【解决方案5】:

        array_walk 只是将函数应用于每个元素,它不会告诉你它是否成功。 array_filter 将执行您要查找的操作,因为它会删除任何与过滤器功能不匹配的元素。

        $result = array_filter(array_column($arr, "number8"), 'is_numeric');
        if (count($result) === count($arr)) {
            // all numeric
        } else {
            // one or more not numeric
        }
        

        注意你可以在这里直接使用is_numeric,因为回调只接受一个参数,即数组元素的值。

        【讨论】:

        • 除非您处理的是非常大的数组(如数万个元素),否则不同数组迭代方法之间的性能不太可能有任何显着差异。
        • $arr 的计数与$result 的计数不同,一个是对整个数组进行计数,一个是对列进行计数。除了count 在这种情况下确实不需要这一事实。 :) 那说它确实有效,只是因为使用了存在于数组中所有项目中的单个列,但它似乎是未来头痛的潜在来源。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-04
        • 1970-01-01
        • 2012-10-12
        • 1970-01-01
        • 1970-01-01
        • 2016-05-03
        • 1970-01-01
        相关资源
        最近更新 更多