How to check if PHP array is associative or sequen

2018-12-31 19:44发布

PHP treats all arrays as associative, so there aren't any built in functions. Can anyone recommend a fairly efficient way to check if an array contains only numeric keys?

Basically, I want to be able to differentiate between this:

$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');

and this:

$assocArray = array('fruit1' => 'apple', 
                    'fruit2' => 'orange', 
                    'veg1' => 'tomato', 
                    'veg2' => 'carrot');

标签: php arrays
30条回答
弹指情弦暗扣
2楼-- · 2018-12-31 20:11

Could this be the solution?

  public static function isArrayAssociative(array $array) {
      reset($array);
      return !is_int(key($array));
  }

The caveat is obviously that the array cursor is reset but I'd say probably the function is used before the array is even traversed or used.

查看更多
人气声优
3楼-- · 2018-12-31 20:12

Actually the most efficient way is thus:

function is_assoc($array){
   $keys = array_keys($array);
   return $keys !== array_keys($keys);
}

This works because it compares the keys (which for a sequential array are always 0,1,2 etc) to the keys of the keys (which will always be 0,1,2 etc).

查看更多
旧人旧事旧时光
4楼-- · 2018-12-31 20:12

This function can handle:

  • array with holes in index (e.g. 1,2,4,5,8,10)
  • array with "0x" keys: e.g. key '08' is associative while key '8' is sequential.

the idea is simple: if one of the keys is NOT an integer, it is associative array, otherwise it's sequential.

function is_asso($a){
    foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
    return FALSE;
}
查看更多
刘海飞了
5楼-- · 2018-12-31 20:12

I compare the difference between the keys of the array and the keys of the result of array_values() of the array, which will always be an array with integer indices. If the keys are the same, it's not an associative array.

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}
查看更多
长期被迫恋爱
6楼-- · 2018-12-31 20:15

answers are already given but there's too much disinformation about performance. I wrote this little benchmark script that shows that the foreach method is the fastest.

Disclaimer: following methods were copy-pasted from the other answers

<?php

function method_1(Array &$arr) {
    return $arr === array_values($arr);
}

function method_2(Array &$arr) {
    for (reset($arr), $i = 0; key($arr) !== $i++; next($arr));
    return is_null(key($arr));
}

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

function method_4(Array &$arr) {
    $idx = 0;
    foreach( $arr as $key => $val ){
        if( $key !== $idx )
            return FALSE;
        $idx++;
    }
    return TRUE;
}




function benchmark(Array $methods, Array &$target){    
    foreach($methods as $method){
        $start = microtime(true);
        for ($i = 0; $i < 1000; $i++)
            $dummy = call_user_func($method, $target);

        $end = microtime(true);
        echo "Time taken with $method = ".round(($end-$start)*1000.0,3)."ms\n";
    }
}



$targets = [
    'Huge array' => range(0, 30000),
    'Small array' => range(0, 1000),
];
$methods = [
    'method_1',
    'method_2',
    'method_3',
    'method_4',
];
foreach($targets as $targetName => $target){
    echo "==== Benchmark using $targetName ====\n";
    benchmark($methods, $target);
    echo "\n";
}

results:

==== Benchmark using Huge array ====
Time taken with method_1 = 5504.632ms
Time taken with method_2 = 4509.445ms
Time taken with method_3 = 8614.883ms
Time taken with method_4 = 2720.934ms

==== Benchmark using Small array ====
Time taken with method_1 = 77.159ms
Time taken with method_2 = 130.03ms
Time taken with method_3 = 160.866ms
Time taken with method_4 = 69.946ms
查看更多
琉璃瓶的回忆
7楼-- · 2018-12-31 20:15

In my opinion, an array should be accepted as associative if any of its keys is not integer e.g. float numbers and empty string ''.

Also non-sequenced integers has to be seen as associative like (0,2,4,6) because these kind of arrays cannot be used with for loops by this way:

$n =count($arr);
for($i=0,$i<$n;$i++) 

The second part of the function below does check if the keys are indexed or not.It also works for keys with negative values. For example (-1,0,1,2,3,4,5)

count() = 7 , max = 5, min=-1



if( 7 == (5-(-1)+1 ) // true
    return false; // array not associative


/** 
 * isAssoc Checks if an array is associative
 * @param $arr reference to the array to be checked
 * @return bool 
 */     
function IsAssoc(&$arr){
    $keys= array_keys($arr);
    foreach($keys as $key){
        if (!is_integer($key))
            return true;
    }
    // if all keys are integer then check if they are indexed
    if(count($arr) == (max($keys)-min($keys)+1))
        return false;
    else
        return true;
}
查看更多
登录 后发表回答