Как проверить, является ли массив PHP ассоциативным или последовательным? - PullRequest
724 голосов
/ 06 октября 2008

PHP обрабатывает все массивы как ассоциативные, поэтому встроенных функций нет. Кто-нибудь может порекомендовать довольно эффективный способ проверить, содержит ли массив только цифровые ключи?

В принципе, я хочу иметь возможность различать это:

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

и это:

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

Ответы [ 51 ]

0 голосов
/ 14 марта 2014
function is_array_assoc($foo) {
    if (is_array($foo)) {
        return (count(array_filter(array_keys($foo), 'is_string')) > 0);
    }
    return false;
}
0 голосов
/ 05 ноября 2008
function isAssoc($arr)
{
    $a = array_keys($arr);
    for($i = 0, $t = count($a); $i < $t; $i++)
    {
        if($a[$i] != $i)
        {
            return false;
        }
    }
    return true;
}
0 голосов
/ 08 февраля 2009

Я просто использую функцию key (). Обратите внимание:

<?php
var_dump(key(array('hello'=>'world', 'hello'=>'world'))); //string(5) "hello"
var_dump(key(array('world', 'world')));                  //int(0)
var_dump(key(array("0" => 'a', "1" => 'b', "2" => 'c'))); //int(0) who makes string sequetial keys anyway????
?>

Таким образом, просто проверяя ложь, вы можете определить, является ли массив ассоциативным или нет.

0 голосов
/ 06 сентября 2018

Или вы можете просто использовать это:

Arr::isAssoc($array)

, который проверит, содержит ли массив любой нечисловой ключ или:

Arr:isAssoc($array, true)

чтобы проверить, является ли массив строго последовательным (содержит автоматически сгенерированные целые ключи 0 до n-1 )

с использованием этой библиотеки.

0 голосов
/ 20 июля 2016

Улучшение от Марка Амери

function isAssoc($arr)
{
    // Is it set, is an array, not empty and keys are not sequentialy numeric from 0
    return isset($arr) && is_array($arr) && count($arr)!=0 && array_keys($arr) !== range(0, count($arr) - 1);
}

Этот тест проверяет, существует ли переменная, является ли она массивом, не является ли она пустым массивом и не являются ли ключи последовательными от 0.

Чтобы увидеть, является ли массив ассоциативным

if (isAssoc($array)) ...

Чтобы узнать, числовой ли он

if (!isAssoc($array)) ...
0 голосов
/ 24 июня 2011

Другой вариант еще не показан, так как он просто не принимает числовые ключи, но мне очень нравится один из Грега:

 /* Returns true if $var associative array */  
  function is_associative_array( $array ) {  
    return is_array($array) && !is_numeric(implode('', array_keys($array)));  
  }
0 голосов
/ 19 апреля 2011

Модификация на самый популярный ответ.
Это требует немного больше обработки, но является более точным.

<?php
//$a is a subset of $b
function isSubset($a, $b)
{
    foreach($a =>$v)
        if(array_search($v, $b) === false)
            return false;

    return true;

    //less effecient, clearer implementation. (uses === for comparison)
    //return array_intersect($a, $b) === $a;
}

function isAssoc($arr)
{
    return !isSubset(array_keys($arr), range(0, count($arr) - 1));
}

var_dump(isAssoc(array('a', 'b', 'c'))); // false
var_dump(isAssoc(array(1 => 'a', 0 => 'b', 2 => 'c'))); // false
var_dump(isAssoc(array("0" => 'a', "1" => 'b', "2" => 'c'))); // false 
//(use === in isSubset to get 'true' for above statement)
var_dump(isAssoc(array("a" => 'a', "b" => 'b', "c" => 'c'))); // true
?>
0 голосов
/ 28 июня 2012

На самом деле я оказался в подобной ситуации, пытаясь взять массив и разобрать его в XML. Имена элементов XML не могут начинаться с цифр, и фрагменты кода, которые я обнаружил, неправильно обрабатывали массивы с числовыми индексами.

Подробности по моей конкретной ситуации ниже

Ответ, предоставленный выше @null (http: // stackoverflow .com / a / 173589/293332), на самом деле был чертовски близок. Я был встревожен, что за него проголосовали: те, кто не понимает регулярное выражение, ведут очень расстраивающие жизни.

В любом случае, исходя из его ответа, вот что я закончил:

/** 
 * Checks if an array is associative by utilizing REGEX against the keys
 * @param   $arr    <array> Reference to the array to be checked
 * @return  boolean
 */     
private function    isAssociativeArray( &$arr ) {
    return  (bool)( preg_match( '/\D/', implode( array_keys( $arr ) ) ) );
}

Дополнительные сведения см. На страницах PCRE Escape и PCRE Syntax .

Моя особая ситуация

Вот пример массива, с которым я имею дело:

Случай А
return  array(
    "GetInventorySummary"  => array(
        "Filters"  => array( 
            "Filter"  => array(
                array(
                    "FilterType"  => "Shape",
                    "FilterValue"  => "W",
                ),
                array(
                    "FilterType"  => "Dimensions",
                    "FilterValue"  => "8 x 10",
                ),
                array(
                    "FilterType"  => "Grade",
                    "FilterValue"  => "A992",
                ),
            ),
        ),
        "SummaryField"  => "Length",
    ),
);

Проблема в том, что ключ filter является переменным. Например:

Дело Б
return  array(
    "GetInventorySummary"  => array(
        "Filters"  => array( 
            "Filter"  => array(
                "foo"   =>  "bar",
                "bar"   =>  "foo",
            ),
        ),
        "SummaryField"  => "Length",
    ),
);

Зачем мне доц. Проверка массива

Если массив, который я преобразовываю, похож на Случай A , то, что я хочу получить, будет:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GetInventorySummary>
    <Filters>
        <Filter>
            <FilterType>Shape</FilterType>
            <FilterValue>W</FilterValue>
        </Filter>
        <Filter>
            <FilterType>Dimensions</FilterType>
            <FilterValue>8 x 10</FilterValue>
        </Filter>
        <Filter>
            <FilterType>Grade</FilterType>
             <FilterValue>A992</FilterValue>
        </Filter>
    </Filters>
    <SummaryField>Length</SummaryField>
</GetInventorySummary>

... Однако, если массив, который я преобразовываю, похож на Случай B , я хочу получить следующее:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GetInventorySummary>
    <Filters>
        <Filter>
            <foo>bar</foo>
            <bar>foo</bar>
        </Filter>
    </Filters>
    <SummaryField>Length</SummaryField>
</GetInventorySummary>
0 голосов
/ 03 октября 2018
/*
iszba - Is Zero Based Array

Detects if an array is zero based or not.

PARAMS:
    $chkvfnc
        Callback in the loop allows to check the values of each element.
        Signature:
            bool function chkvfnc($v);
            return:
                true    continue looping
                false   stop looping; iszba returns false too.

NOTES:
○ assert: $array is an array.
○ May be memory efficient;
  it doesn't get extra arrays via array_keys() or ranges() into the function.
○ Is pretty fast without a callback.
○ With callback it's ~2.4 times slower.
*/
function iszba($array, $chkvfnc=null){

    $ncb = !$chkvfnc;
    $i = 0;

    foreach($array as $k => $v){
        if($k === $i++)
            if($ncb || $chkvfnc($v))
                continue;

        return false;
    }

    return true;
}

• Без обратного вызова это ~ 30% быстрее, чем текущий ведущий ответ, и, возможно, более эффективное использование памяти.

• Отмените ответ, чтобы узнать, следует ли считать массив ассоциативным.

0 голосов
/ 19 июня 2012

По моему мнению, массив должен быть принят как ассоциативный, если любой из его ключей не является целым, например числа с плавающей точкой и пустая строка ''.

Также непоследовательные целые числа должны рассматриваться как ассоциативные (0,2, 4, 6), потому что этот тип массивов нельзя использовать для циклов таким образом:

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

Вторая часть функции ниже проверяет, проиндексированы ли ключи или нет. Это также работает для ключей с отрицательными значениями. Например (-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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...