我发现在PHP中(或者我可能找不到),缺少适当的is_numeric_array($array)函数。所以我创建了一个。问题是我认为这不好,也不知道如何改进。

有什么建议吗?

我的第一个功能

function is_numeric_array($array)
{
    $i = 0;
    foreach ($array as $a => $b) { if (is_int($a)) { ++$i; } }
    if (count($array) === $i) { return true; }
    else { return false; }
}

is_numeric_array(array(0,0,0,0,0)); // true
is_numeric_array(array('str' => 1, 'str2' => 2, 'str3' => 3)); // false


示例

根据要求,我提供了一个有关如何有用的示例。

function is_numeric_array($array)
{
    # Code below
}

function someFunction($array)
{
    if (is_numeric_array($array))
    {
        $query = $array[0];
        $param = $array[1];
        $fetch = $array[2];
    }
    else
    {
        $query = $array['query'];
        $param = $array['param'];
        $fetch = $array['fetch'];
    }

    # Do your sql/pdo stuff here
}

# This use is the same of ...
someFunction(array(
    'PDO SQL STATEMENT', 
    array('param1' => 1, 'param2' => 2, 'param3' => 3),
    true
));

# ... this one.
someFunction(array(
    'query' => 'PDO SQL STATEMENT',
    'param' => array('param1' => 1, 'param2' => 2, 'param3' => 3),
    'fetch' => true
));

# To choose one form instead of the other is coder's decision
# Also I know it is useless but I was just wondering why anybody actually looked forward this function


评论

我只是好奇,您能为此提供用例吗?

做完了,希望你喜欢它。

它们都是坏的=)这是唯一正确的方法:gist.github.com/1272230

我读的越多,我就越困惑。您似乎在确定数组是否具有关联性,而我将本主题读为“确定所有数组值是否均为数字/整数”。此处以is_assoc检查的简单方法为例:stackoverflow.com/a/173479/1695680

抱歉,经过进一步考虑,链接的答案不太可靠;您实际上想要修改下一个答案:stackoverflow.com/a/4254008/1695680以使用“ is_int”而不是“ is_string”

#1 楼

除了使用计数器来计算条件为真的键之外,您还可以在找到不是int的键后立即返回false,如果循环到达末尾而没有找到这样的键,则返回true: />
foreach ($array as $a => $b) {
    if (!is_int($a)) {
        return false;
    }
}
return true;


这样做的好处是它会短路(即一旦找到不是int的键,它将停止迭代)并摆脱计数器。

评论


\ $ \ begingroup \ $
array_fill(3,5,0)怎么样?您认为数字数组吗?
\ $ \ endgroup \ $
–鲁迪
2011年10月8日,12:14

\ $ \ begingroup \ $
而不是使用is_int($ a),请使用($ a!==(int)$ a),它将快10倍。
\ $ \ endgroup \ $
–布卡贝
2014年11月1日19:43

#2 楼

在@ sepp2k答案(+1)上稍作改进(删除一些工具会吐出“未使用的变量警告”):线性数组:

foreach (array_keys($array) as $a)) {
    if (!is_int($a)) {
        return false;
    }
}
return true;


或@RobertPitt的解决方案:)(也在那里+1)

但是我的要点是:
您为什么需要这个,我从来没有用过这样的东西,可能是解决方案是更改,而API设计缺陷或数据结构缺陷在某处?还没有,但是可以。

对OP的响应:

我正在为需要3键数组的查询构建db方法。如果数组是数字数组,则顺序必须是:语句,参数,提取。如果不是这样,那么编码器将指定密钥字符串,顺序可以不同,并且三个必需参数中的两个可以为空。 :)

return array_merge($array) === $array;


也许我误解了一点,但它应该弄清楚如何用另一种支票来构建它:)

my_db_function(
    array("myquery", array("params", "..."), "myfetchmode")
);
// or 
my_db_function(
    array("params" => "myquery", "fetchmode" => "myfetchmode, "params" => array("myparams", "...) )
); 


那仍然是一个很大的代码块,但是我不想缩短它,并且冒着糟糕的可读性的风险。

我要怎么做,就是创建一个my_db_stuff_param_helper($ aParams),它将始终返回一个包含3个键的数组,这些键填充有真实值(如果没有传递任何值,则为默认键) br />
function my_db_fuction($statement) {

    if(isset($statement["query"])) { // Assoc 'Mode'
        $query = $statement["query"];
        if(isset($statement["params"])) { $params = $statement["params"]; } 
        else { $params = array(); }
        if(isset($statement["fetchmode"])) { $fetchmode = $statement["fetchmode"]; }
        else { $fetchmode = "select"; // optional param, default value here

    } else if(isset($statement[0]) { // Linear Array Mode

        $query = $statement[0];
        if(isset($statement[1])) { $params = $statement[1]; } 
        else { $params = array(); }
        if(isset($statement[2])) { $fetchmode = $statement[2]; }
        else { $fetchmode = "select"; // optional param, default value here

    } else {
         // Error, misformed format
    }
    // Now we got our 3 variables :)
}


类似的东西“感觉”(主观,我知道)比构建通用函数进行键检查更好。 (我猜是isset($ statement [“ query”])而不是is_numeric_array我要归结为:)

评论


\ $ \ begingroup \ $
我需要它,因为我正在创建一个方法,根据它的编写方式,它必须以不同的方式表现。
\ $ \ endgroup \ $
–鞋子
2011-1-25在18:29

\ $ \ begingroup \ $
您正在做的事情迫使您去做某事,因此您需要这种方法。我是说,也许如果您做不同的事情,您将不需要它。对不起,我不知道如何使自己更清晰,但我读到您的回答为“我需要这个,因为我需要这个”,我只是建议也许您不需要:)而且由于这是codereview而不是SO i我提到了它,而不仅仅是提供(至少对我来说)显而易见的答案的代码片段:)
\ $ \ endgroup \ $
– edorian
2011年1月25日20:26

\ $ \ begingroup \ $
我明白你的意思。我正在为需要3键数组的查询构建db方法。如果数组是数字数组,则顺序必须是:语句,参数,提取。如果不是这样,那么编码器将指定键串,顺序可以不同,并且三个必需参数中的两个可以为空。我知道它很奇怪,我将对其进行编辑,但是我只是想知道是否不存在适当的功能。
\ $ \ endgroup \ $
–鞋子
2011年1月26日7:37



\ $ \ begingroup \ $
编辑我的回答作为回应,可能有点夸张了:)
\ $ \ endgroup \ $
– edorian
2011年1月26日8:33

\ $ \ begingroup \ $
没考虑过这种方法。感谢您提供它。但是,让我们面对现实,PHP有很多无用的函数,为什么不将is_numeric_array()放入内核? 看看那个eval()函数,我的is_numeric_array()函数不是更有用吗?
\ $ \ endgroup \ $
–鞋子
11年1月27日在18:16

#3 楼

最初,我没有意识到您要检查键是否为整数。如果执行此操作的原因是要确保键分别是0、1、2、3、4等作为索引数组而不是关联数组,则可以使用以下命令:

function is_numeric_array($arr)
{
    return array_keys($arr) === range(0,(count($arr)-1));
}

/*
    * Tests
*/
var_dump(is_numeric_array(array('a', 'b', 'c'))); // true
var_dump(is_numeric_array(array("0" => 'a', "1" => 'b', "2" => 'c'))); // true
var_dump(is_numeric_array(array("1" => 'a', "0" => 'b', "2" => 'c'))); // false
var_dump(is_numeric_array(array("a" => 'a', "b" => 'b', "c" => 'c'))); // false


要求的基准测试结果:

以下是用于测试执行情况的代码:

$array = array();
for($i=0;$i<=500000;$i++)
{
    $array[] = "some_string";
}

$m_initial = memory_get_usage();
is_numeric_array($array);
$increase = memory_get_usage() - $m_initial;


您可以从上面看到,我测试了具有500K字符串的线性数组:

$increase的值显示为65032(以字节为单位)。如果我们转换为KB,则大约是64位舍入。以KB为单位的结果显示63.507,我认为还可以。

评论


\ $ \ begingroup \ $
它实际上仅检查值,而不检查键。我错了吗?
\ $ \ endgroup \ $
–鞋子
2011年1月25日18:11

\ $ \ begingroup \ $
在其中添加了$ key。
\ $ \ endgroup \ $
– RobertPitt
2011年1月25日在18:13

\ $ \ begingroup \ $
array_filter的回调仅将数组值作为参数。您需要先获取array_keys,然后对其进行过滤。
\ $ \ endgroup \ $
– Mchl
2011年1月25日18:18



\ $ \ begingroup \ $
是的,它被废弃了,我有点不太坚持,应该做我的研究。
\ $ \ endgroup \ $
– RobertPitt
2011年1月25日在18:22

\ $ \ begingroup \ $
好吧,我想第二个示例返回false,因为您作为编码器定义了一个特定的键。
\ $ \ endgroup \ $
–鞋子
2011年1月25日18:31

#4 楼

好的,这是确保一致性和正确命名约定的镜头(由于numericint意味着不同的东西,所以彼此之间毫无意义...): >现在,对于更多面向对象的方法,我将构建一个filteriterator:如果要验证,可以执行以下操作:

function isNumericArray(array $array) {
    foreach ($array as $a => $b) {
        if (!is_numeric($a)) {
            return false;
        }
    }
    return true;
}

function isIntArray(array $array) {
    foreach ($array as $a => $b) {
        if (!is_int($a)) {
            return false;
        }
    }
    return true;
}


评论


\ $ \ begingroup \ $
+1和FilterIterator的区别。唯一可以改进的是仅检查数组值。无需在整个阵列上运行。
\ $ \ endgroup \ $
– kaiser
2014年3月24日在1:33



#5 楼

一旦找到一个不是int的元素,该函数就会消失,从而使该函数对大型数组更有效。


评论


\ $ \ begingroup \ $
那和他的代码有什么不同?除非我缺少某些内容,否则这将检查值是否为整数,而不是键。如果键不是整数,代码也会导致错误。
\ $ \ endgroup \ $
–sepp2k
2011-1-25在16:42



\ $ \ begingroup \ $
另外,它返回$ i而不是返回$ 1。
\ $ \ endgroup \ $
–鞋子
2011-1-25在16:53

\ $ \ begingroup \ $
另外,我不确定计数是如何工作的,但是它可能会移动数组,导致您将其遍历两次。
\ $ \ endgroup \ $
– Mark Loeser
2011年1月25日在17:08

\ $ \ begingroup \ $
... while循环上也没有停止条件。变了
\ $ \ endgroup \ $
– Michael K
2011-1-25在17:27

\ $ \ begingroup \ $
我也会尝试krsort($ array,SORT_STRING);第一。这会将大多数非数字键移到数组的开头。如果可以提高性能,则需要进行基准测试。
\ $ \ endgroup \ $
– Mchl
2011-1-25在18:03



#6 楼

这可能会更有效:是整数,但是如果数组是索引的(非关联),则为此使用array_values()可以解决问题:

function is_numeric_array($array)
{
    $array = array_keys($array);

    if ($array === array_filter($array, 'is_int'))
    {
        return true;
    }

    return false;
}


评论


\ $ \ begingroup \ $
这应该是公认的解决方案! array_values FTW!
\ $ \ endgroup \ $
–TomášFejfar
17 Mar 29 '17 at 20:23

#7 楼

如果您实际上是在尝试确定它是否是顺序整数数组而不是关联整数,即json_encode可以将数组与对象进行比较,那么这可能是最快的方法:

function is_normal_array($arr) {
    $c = count($arr);
    for ($i = 0; $i < $c; $i++) {
        if (!isset($arr[$i])) {
            return false;
        }
    }
    return true;
}


...当然,最快的代码是您永远不会运行的代码,因此请考虑您是否真的需要这样做,并且仅在执行时使用它。

评论


\ $ \ begingroup \ $
这应该比其他人发布的foreach解决方案要快,但是算法并不一致。 foreach解决方案针对array(0 =>'a',1 =>'b',3 =>'d')返回true,而我的返回false。
\ $ \ endgroup \ $
–杰伊·帕罗林(Jay Paroline)
2011-1-27在7:24

#8 楼

这是一则古老的文章,但是如果您正在寻找一个较短但仍然优雅的解决方案,请使用此方法:

太短了。干杯