PHP 배열이 연관인지 순차적인지 확인하는 방법은 무엇입니까?


781

PHP는 모든 배열을 연관성으로 취급하므로 내장 함수가 없습니다. 배열에 숫자 키만 포함되어 있는지 확인하는 매우 효율적인 방법을 추천 할 수 있습니까?

기본적으로 나는 이것을 구별 할 수 있기를 원합니다.

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

이:

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

382
코드에 버그가 있습니다. 토마토는 과일입니다.
Olle Härstedt

9
이 방법에는주의 사항이 있지만 종종 if (isset($array[0]))간단합니다. 간단하고 빠릅니다. 물론 배열이 비어 있지 않은지 확인해야하며 배열의 가능한 내용에 대해 알고 있어야합니다 (숫자 / 연관 혼합 또는 비 순차적 혼합 등).
Gras Double

@ OlleHärstedt 미국 고등 법원 따르지 않습니다 . ;-)
MC 황제

답변:


622

그다지 동등하지 않은 두 가지 질문을했습니다.

  • 첫째, 배열에 숫자 키만 있는지 확인하는 방법
  • 둘째, 배열에 0부터 시작하는 순차적 숫자 키 가 있는지 확인하는 방법

실제로 필요한 행동을 고려하십시오. (여러분의 목적을 위해 할 수도 있습니다.)

첫 번째 질문 (간단히 모든 키가 숫자인지 확인)은 kurO 선장이 잘 대답합니다 .

두 번째 질문 (배열이 0 인덱싱되고 순차적인지 여부 확인)의 경우 다음 기능을 사용할 수 있습니다.

function isAssoc(array $arr)
{
    if (array() === $arr) return false;
    return array_keys($arr) !== range(0, count($arr) - 1);
}

var_dump(isAssoc(['a', 'b', 'c'])); // false
var_dump(isAssoc(["0" => 'a', "1" => 'b', "2" => 'c'])); // false
var_dump(isAssoc(["1" => 'a', "0" => 'b', "2" => 'c'])); // true
var_dump(isAssoc(["a" => 'a', "b" => 'b', "c" => 'c'])); // true

32
매우 우아한 솔루션. 빈 배열의 (모호한) 경우 TRUE를 반환합니다.
Jonathan Lidbeck

30
순차 배열을 연관 배열의 특별한 경우로 생각하는 것이 더 유용하다고 생각합니다. 따라서 모든 배열은 연관성이 있지만 일부만 순차적입니다. 따라서 함수 isSequential()는보다 더 의미가 isAssoc()있습니다. 이러한 함수에서 빈 배열 순차적으로 표시 되어야 합니다. 공식은입니다 array() === $arr || !isAssoc($arr).
donquixote

18
배열이 비어 있지 않지만 0에 요소가없는 경우 명확하게 연관되어 있기 때문에 모든 키를 추출하기 전에 isset ($ arr [0])이 false인지 확인하면 잠재적 인 CPU 시간과 메모리를 많이 피할 수 있다고 생각합니다. 위치. "가장 큰"실제 연관 배열은 문자열을 키로 가지고 있기 때문에 이러한 기능의 일반적인 경우를위한 훌륭한 최적화가되어야합니다.
OderWat

10
@OderWat- 0 요소가 null 값이면 isset이 잘못 false를 반환하기 때문에 array_key_exists대신 최적화를 사용해야 합니다 isset. 일반적으로 null 값은 이러한 배열에서 합법적 인 값이어야합니다.
OCDev September

@MAChitgarha, 귀하의 편집은 이유에 대한 설명없이 함수의 동작을 변경했으며 실제로 수행해야 할 사항에 대한 위의 산문의 설명과 모순되었습니다. 나는 그것을 되 돌렸다.
Mark Amery

431

배열에 정수가 아닌 키가 있는지 여부를 확인하려면 (어레이가 순차적으로 색인화되는지 0 색인화되지 않았는지)

function has_string_keys(array $array) {
  return count(array_filter(array_keys($array), 'is_string')) > 0;
}

하나 이상의 문자열 키 $array가 있으면 연관 배열로 간주됩니다.


22
이 방법은 생각보다 훨씬 낫습니다. count (filtered_array) == count (original_array)이면 assoc 배열입니다. count (filtered_array) == 0이면 인덱스 배열입니다. count (filtered_array) <count (original_array)이면 배열에 숫자 키와 문자열 키가 모두 있습니다.
Jamol

5
@MikePretzlaw는 물론 반복합니다. 배열의 모든 키를 보지 않고 배열의 모든 키가 정수인지 여부를 결정하는 가능한 방법은 없습니다. 아래에서보아야 할 비 반복적 인 대안은 다음과 같은 것으로 가정합니다 $isIndexed = array_values($arr) === $arr;. 내가 묻는 질문 : 어떻게 array_values()작동 한다고 생각 하십니까? ===배열에 어떻게 적용 되는가? 대답은 그들이 것을 물론이다 또한 배열을 반복.
Mark Amery

4
@ARW "PHP는 가능하다면 배열 정의에서 모든 것을 int로 캐스팅하는 것 같습니다." -그래, 그게 정확히 무슨 일이야. 가장 큰 WTF는 심지어 이것을 뜬다. 시도 var_dump([1.2 => 'foo', 1.5 => 'bar']);하면 배열을 얻는다는 것을 알게 될 것 [1 => 'bar']입니다. 키의 원래 유형을 찾는 방법은 없습니다. 예,이 모든 것이 끔찍합니다. PHP의 배열은 언어의 최악의 부분이며, 손상의 대부분은 돌이킬 수 없으며 전통적인 배열과 전통적인 해시 맵에 단일 구조를 사용한다는 아이디어 덕분에 처음부터 끔찍합니다.
Mark Amery

30
@MarkAmery 위의 내용은 단순하지만 100 % 배열을 보장합니다. 특히 큰 배열을 다루는 경우 string 또는 int를 확인하고 처음 발견 한 경우 더 효율적입니다. function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
생각

1
@Thought 코드는 매우 빠르게 작동하지만 순차 배열을 감지 할 수 없습니다 . 예제 array(1 => 'a', 0 => 'b', 2 => 'c')false(연속 배열) 이되고 ( true연관 배열)이됩니다. toolsqa.com/data-structures/array-in-programming 열쇠가 오름차순이어야하는지 잘 모르겠습니다. (0, 1, ...)
vee

132

확실히 이것은 더 나은 대안입니다.

<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;

52
이것은 배열의 값을 복제하여 잠재적으로 매우 비쌉니다. 배열 키를 검사하는 것이 훨씬 좋습니다.
meagar

8
방금 사용한 ==; 여기에 ===가 필요하다고 생각하지 않습니다. 그러나 "unset and it does not work"에 답하기 위해 : 일단 첫 번째 요소를 설정 해제하면 더 이상 0에서 시작하는 정수 인덱스 배열이 아닙니다. 따라서 IMO가 작동합니다.
grantwparks

4
@grantwparks에 동의하십시오 : 희소 배열은 색인화되지 않습니다. 흥미롭게도 인덱스 배열의 중간에서 요소를 실제로 삭제할 수있는 방법이 없기 때문에 PHP는 기본적으로 모든 배열을 연관성으로 선언하고 숫자는 단지 '나에게 중요한 열쇠입니다'버전입니다.
RickMeasham

7
내가 가진 유일한 문제 ===는 키에만 관심이 있지만 값이 같은지 확인하는 데 시간이 낭비 된다는 것입니다. 이런 이유로 나는 $k = array_keys( $arr ); return $k === array_keys( $k );버전을 선호합니다 .
Jesse

5
덧붙여서 이것은 순서가 잘못된 숫자 키로 지정된 배열에서는 실패합니다. 예를 들어 $ myArr = 배열 ​​(0 => 'a', 3 => 'b', 4 => 1, 2 => 2, 1 => '3'); 잠재적 인 해결 방법 중 하나는 테스트를 수행하기 전에 ksort ($ arr)를 실행하는 것입니다.
Scott

77

이 질문에 대한 많은 의견자는 PHP에서 배열이 어떻게 작동하는지 이해하지 못합니다. 로부터 어레이 설명서 :

키는 정수 또는 문자열 일 수 있습니다. 키가 정수의 표준 표현이면 키로 해석됩니다 (예 : "8"은 8로 해석되고 "08"은 "08"로 해석됩니다). 키의 부동 소수점은 정수로 잘립니다. 인덱스 및 연관 배열 유형은 PHP에서 동일한 유형이며 정수 및 문자열 색인을 모두 포함 할 수 있습니다.

다시 말해, 배열 키 "8"은 항상 정수 8로 자동 변환되기 때문에 "8"과 같은 것은 없습니다. 따라서 정수와 숫자 문자열을 구별하려는 시도는 필요하지 않습니다.

array_keys ()처럼 배열의 일부 또는 foreach처럼 복사하지 않고 정수가 아닌 키가 있는지 배열을 검사하는 가장 효율적인 방법을 원한다면 :

function keyedNext( &$arr, &$k){
    $k = key($arr);
    return next($arr);
}

for ($k = key(reset($my_array)); is_int($k); keyedNext($my_array,$k))
    $onlyIntKeys = is_null($k);

이것은 현재 배열 위치가 유효하지 않을 때 key ()가 NULL을 반환하고 NULL이 유효한 키가 될 수 없기 때문에 작동합니다 (배열 키로 NULL을 사용하려고하면 ""로 자동 변환됩니다).


비 순차 정수 키에는 작동하지 않습니다. [2 => 'a', 4 => 'b']로 시도하십시오.
DavidJ

2
@DavidJ, "작동하지 않습니다"는 무슨 뜻입니까? 모든 키가 정수인지 확인합니다. 게시 한 것과 같은 배열을 "숫자 배열"로 간주해서는 안된다고 주장하고 있습니까?
coredumperror 2018 년

7
비 연관 배열에 이르기까지 키가 있어야 0로를 count($array)-1이 엄격한 순서. 예비 점검 is_array()이 도움 이 될 수 있습니다. 키 순서를 확인하기 위해 증가하는 변수를 추가하십시오. for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k;그러면 거래가 해결됩니다.
ofavre

2
foreach명시적인 반복 대신 사용 하는 것이 약 두 배 빠릅니다.
ofavre

1
이것을 기능으로 만들고 싶다면 : function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
GreeKatrina

39

OP에 명시된 바와 같이 :

PHP는 모든 배열을 연관성으로 취급합니다

배열이 연관 되어 있는지 확인하는 함수를 작성하는 것은 합리적이지 않습니다 (IMHO) . 먼저 가장 먼저 : PHP 배열의 키는 무엇 입니까? :

키는 어느 쪽이 될 수 정수 또는 문자열 .

이는 가능한 세 가지 경우가 있음을 의미합니다.

  • 사례 1. 모든 키는 숫자 / 정수 입니다.
  • 사례 2. 모든 키는 문자열 입니다.
  • 경우 3. 일부 키는 문자열 이고 일부 키는 숫자 / 정수 입니다.

다음과 같은 기능으로 각 사례를 확인할 수 있습니다.

사례 1 : 모든 키는 숫자 / 정수 입니다.

참고 : 이 함수는 빈 배열에 대해서도 true 를 반환 합니다 .

//! Check whether the input is an array whose keys are all integers.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are all integers.
*/
function IsArrayAllKeyInt($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_unique(array_map("is_int", array_keys($InputArray))) === array(true);
}

사례 2 : 모든 키는 문자열 입니다.

참고 : 이 함수는 빈 배열에 대해서도 true 를 반환 합니다 .

//! Check whether the input is an array whose keys are all strings.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are all strings.
*/
function IsArrayAllKeyString($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_unique(array_map("is_string", array_keys($InputArray))) === array(true);
}

경우 3. 일부 키는 문자열 이고 일부 키는 숫자 / 정수 입니다.

참고 : 이 함수는 빈 배열에 대해서도 true 를 반환 합니다 .

//! Check whether the input is an array with at least one key being an integer and at least one key being a string.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array with at least one key being an integer and at least one key being a string.
*/
function IsArraySomeKeyIntAndSomeKeyString($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return count(array_unique(array_map("is_string", array_keys($InputArray)))) >= 2;
}

다음과 같습니다.


이제 배열 이 우리 모두에게 익숙한 "정품"배열 이 되려면 다음 을 의미합니다.

이하의 기능으로 확인할 수 있습니다.

사례 3a. 키는 숫자 / 정수 , 순차0부터 시작합니다 .

참고 : 이 함수는 빈 배열에 대해서도 true 를 반환 합니다 .

//! Check whether the input is an array whose keys are numeric, sequential, and zero-based.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are numeric, sequential, and zero-based.
*/
function IsArrayKeyNumericSequentialZeroBased($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_keys($InputArray) === range(0, count($InputArray) - 1);
}

주의 사항 / 함정 (또는 PHP의 배열 키에 대한 더 독특한 사실)

정수 키

이 배열의 키는 정수입니다 .

array(0 => "b");
array(13 => "b");
array(-13 => "b");          // Negative integers are also integers.
array(0x1A => "b");         // Hexadecimal notation.

문자열 키

이 배열의 키는 문자열입니다 .

array("fish and chips" => "b");
array("" => "b");                                   // An empty string is also a string.
array("stackoverflow_email@example.com" => "b");    // Strings may contain non-alphanumeric characters.
array("stack\t\"over\"\r\nflow's cool" => "b");     // Strings may contain special characters.
array('$tα€k↔øv∈rflöw⛄' => "b");                    // Strings may contain all kinds of symbols.
array("functіon" => "b");                           // You think this looks fine? Think again! (see https://stackoverflow.com/q/9246051/1402846)
array("ま말轉转ДŁ" => "b");                         // How about Japanese/Korean/Chinese/Russian/Polish?
array("fi\x0sh" => "b");                            // Strings may contain null characters.
array(file_get_contents("https://www.google.com/images/nav_logo114.png") => "b");   // Strings may even be binary!

문자열처럼 보이는 정수 키

당신이 키를 생각한다면 array("13" => "b")A는 문자열 , 당신은 잘못입니다 . 문서 에서 여기 :

유효한 정수를 포함하는 문자열은 정수 유형으로 캐스트됩니다. 예를 들어 "8"키는 실제로 8 아래에 저장됩니다. 반면 "08"은 유효한 10 진수가 아니기 때문에 캐스트되지 않습니다.

예를 들어,이 배열의 키는 정수입니다 .

array("13" => "b");
array("-13" => "b");                        // Negative, ok.

그러나 이러한 배열의 핵심은 문자열입니다 .

array("13." => "b");
array("+13" => "b");                        // Positive, not ok.
array("-013" => "b");
array("0x1A" => "b");                       // Not converted to integers even though it's a valid hexadecimal number.
array("013" => "b");                        // Not converted to integers even though it's a valid octal number.
array("18446744073709551616" => "b");       // Not converted to integers as it can't fit into a 64-bit integer.

더군다나 의사에 따르면

정수의 크기는 플랫폼에 따라 다르지만 최대 약 20 억 개의 값이 일반적인 값 (32 비트 부호)입니다. 64 비트 플랫폼은 보통 최대 32 비트 인 Windows를 제외하고 최대 약 9E18입니다. PHP는 부호없는 정수를 지원하지 않습니다.

따라서이 배열의 키 는 정수 이거나 정수 가 아닐 수 있습니다 -플랫폼에 따라 다릅니다.

array("60000000000" => "b");                // Array key could be integer or string, it can fit into a 64-bit (but not 32-bit) integer.

더 나쁜 것은, 정수가 2 31 = 2,147,483,648 경계에 가까우면 PHP는 버그 가있는 경향이 있습니다 ( 버그 51430 , 버그 52899 참조 ). 예를 들어, (윈도우 7에 XAMPP 1.7.7에서 PHP 5.3.8) 내 지역 환경에 제공var_dump(array("2147483647" => "b"))

array(1) {
    [2147483647]=>
    string(1) "b"
}   

그러나 코드 패드 (PHP 5.2.5) 의이 라이브 데모 에서는 동일한 표현으로

array(1) {
    ["2147483647"]=>
    string(1) "b"
}

따라서 키는 유효한 부호있는 32 비트 정수 이지만 한 환경 에서는 정수 이지만 다른 환경에서는 문자열 입니다 .2147483647


2
아래에서 언급했듯이 검사 할 배열에 복제 배열을 생성하여 큰 배열에 매우 비싸고 공유 호스트에서 메모리 부족 충돌이 발생할 수 있습니다.
podperson 2016 년

35

속도 :

function isAssoc($array)
{
    return ($array !== array_values($array));
}

메모리 방식 :

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

다음 배열 : array (02 => 11,1,2,456); 심지어 02 ===이 경우 상기 알고리즘을 이용하여 숫자 키를 갖지 않는 것으로 도시된다
Galileo_Galilei

20
function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}

2
이것은 (내 의견 당시) 다음을 다룰 수 있는 유일한 대답입니다. $ array = array (0 => 'blah', 2 => 'yep', 3 => 'wahey')
Shabbyrobe

하지만 array('1'=>'asdf', '2'=>'too')실제로는 그렇지 않은 동안 연관 배열로 간주됩니다 (키는 실제로 문자열 임)
kurO 선장

1
@CaptainkurO 숫자를 의미합니다. 연관 배열입니다.
devios1

1
이 함수는 true키가 0, 정수 (양수 만), 빈 문자열 또는 위의 문자열 조합 (예 : 문자열 "09")을 반환 합니다. 이 기능은 키의 순서를 고려하지 않습니다. 그래서 array(0=>'blah', 2=>'yep', 3=>'wahey'), array(0=>'blah', 2=>'yep', 1=>'wahey')하고 array('blah', 'yep', 'wahey')있는 동안,이 기능에 따라 모든 연관되어 array('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')없습니다.
Pang

@CaptainkurO 당신이 잘못되었습니다. '1'과 '2'는 정수로 저장됩니다. 2011 년 5 월 11 일 19:34에 다람쥐 답변의 인용 부분을 읽으십시오. PHP는 정수처럼 보이는 문자열 키를 저장하지 않습니다. 그것들을 정수로 변환합니다.
Buttle Butkus

20

실제로 가장 효율적인 방법은 다음과 같습니다.

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

이것은 (순차적 인 배열에 대해 항상있는 0,1,2 등)의 키를 비교하기 때문에 작동 (것 키의 키에 항상 0, 1, 2 등이 될).


1
영리하지만 좋지는 않습니다. 이것이 "가장 효율적인"이유는 무엇입니까? array_keys ($ a)를 range (0, count ($ a))와 비교하는 것이 훨씬 더 읽기 쉽습니다. 가장 영리한 솔루션은 내 경험상 가장 좋은 솔루션은 아닙니다. 특히 영리 할 때 명백하고 깨끗한 대안보다 가치가 없습니다.
Shane H

4
이 기능은 반환 true을 위해 array(1=>"a")하지만 false위해 array("a"=>"a"). !=로 교체 하면 더 의미 가 !==있습니다.
Pang

1
@ 팡 당신이 맞습니다. 나는 당신의 의견이 처음에는 반드시 틀렸다고 생각했지만 놀랍게도 [0] == ['a']PHP에서는 ( 0 == 'a'실제로 0 == 'banana') 있습니다. PHP의 ==연산자는 미쳤다.
Mark Amery

2
비 순차 정수 인덱스를 찾을 때까지 array_keys를 호출하는 것 외에는 확인하는 것만으로는 효율적이지 않습니다. 후드 아래에서 어쨌든 그렇게 하고 있지만 이미 큰 배열을 복제했습니다.
podperson

17

난 둘 다 사용했습니다 array_keys($obj) !== range(0, count($obj) - 1)array_values($arr) !== $arr(두 번째는 첫 번째보다 저렴하지만, 서로의 DUALS있는)하지만 모두 매우 큰 배열 실패.

때문이다 array_keys하고 array_values(그들은 대략 그 원래의 크기의 새로운 배열을 구축 이후) 모두 매우 비용이 많이 드는 작업이다.

다음 기능은 위에 제공된 방법보다 강력합니다.

function array_type( $obj ){
    $last_key = -1;
    $type = 'index';
    foreach( $obj as $key => $val ){
        if( !is_int( $key ) || $key < 0 ){
            return 'assoc';
        }
        if( $key !== $last_key + 1 ){
            $type = 'sparse';
        }
        $last_key = $key;
    }
    return $type;
}

또한 희소 배열을 연관 배열과 구별하지 않으려면 'assoc'if블록 에서 간단히 돌아올 수 있습니다 .

마지막으로이 페이지의 많은 "솔루션"보다 "우아한"것처럼 보이지만 실제로는 훨씬 더 효율적입니다. 거의 모든 연관 배열이 즉시 감지됩니다. 인덱스 배열 만 철저히 검사하며, 위에서 설명한 방법은 인덱스 배열을 철저하게 검사 할뿐만 아니라 복제합니다.


13

다음 두 함수가 '배열이 연관 적이거나 숫자인지 여부'를 확인하는 가장 좋은 방법이라고 생각합니다. '숫자'는 숫자 키 또는 순차 숫자 키만 의미 할 수 있으므로 두 가지 기능이 아래에 나열되어 있습니다.

function is_indexed_array(&$arr) {
  for (reset($arr); is_int(key($arr)); next($arr));
  return is_null(key($arr));
}

function is_sequential_array(&$arr, $base = 0) {
  for (reset($arr), $base = (int) $base; key($arr) === $base++; next($arr));
  return is_null(key($arr));
}

첫 번째 함수는 각 키가 정수 값인지 확인합니다. 두 번째 함수는 각 키가 정수 값인지 확인하고 모든 키가 $ base에서 순차적으로 시작하는지 확인합니다. 기본값은 0으로 설정되므로 다른 기본 값을 지정할 필요가없는 경우 생략 할 수 있습니다. key ($ my_array)는 읽기 포인터가 배열의 끝을지나 이동하면 null을 반환합니다. 이는 for 루프를 끝내고 for 키 뒤의 명령문이 모든 키가 정수인 경우 true를 반환합니다. 그렇지 않으면 키가 문자열 유형이므로 루프가 조기에 종료되고 for 루프 뒤의 명령문은 false를 리턴합니다. 후자의 함수는 각 비교 후 $ base에 1을 추가하여 다음 키가 올바른 값인지 확인할 수 있습니다. 엄격한 비교를 통해 키가 정수 유형인지 확인합니다. for 루프의 첫 번째 섹션에서 $ base = (int) $ base 부분은 $ base가 생략되거나 정수만 사용하여 호출 된 경우 생략 될 수 있습니다. 그러나 모든 사람을 확신 할 수 없기 때문에 그대로 두었습니다. 어쨌든 그 진술은 한 번만 실행됩니다. 나는 이것이 가장 효율적인 솔루션이라고 생각합니다.

  • 현명한 메모리 : 데이터 또는 키 범위를 복사하지 않습니다. array_values ​​또는 array_keys를 수행하는 것이 더 짧아 보일 수 있지만 (코드가 적음) 전화를 걸면 백그라운드에서 진행되는 작업을 명심하십시오. 그렇습니다. 다른 해결책보다 더 많은 (눈에 보이는) 진술이 있지만 그것은 중요하지 않습니다.
  • 현명한 시간 : 데이터 및 / 또는 키를 복사 / 추출하는 데 시간이 걸리는 것 외에도이 솔루션은 foreach를 수행하는 것보다 더 효율적입니다. 다시 foreach는 표기법이 더 짧기 때문에 일부에게는 더 효율적으로 보일 수 있지만 백그라운드에서 foreach는 reset, key를 호출하고 다음으로 반복합니다. 그러나 또한 종료 조건을 확인하기 위해 유효한 호출을 수행합니다. 정수 확인과의 조합으로 인해 여기서 피할 수 있습니다.

배열 키는 정수 또는 문자열 일 수 있으며 "1"(단, "01"은 아님)과 같은 숫자로 된 문자열은 정수로 변환됩니다. 배열을 순차적으로 만들고 싶다면 정수 키를 확인하는 것만 필요한 것 외에도 계산이 필요합니다. 당연히 is_indexed_array가 false를 반환하면 배열을 연관성으로 볼 수 있습니다. 사실 모두가 그렇기 때문에 나는 '보았다'고 말합니다.


1
이것이 가장 좋은 대답입니다. "연관"또는 "숫자"배열의 정의는 특정 상황에 따라 다릅니다.
Pato

foreach가 여기에 사용 된 방법보다 효율성이 떨어지면 두 가지 다른 기능을 사용하는 불편 함을 제외하고이 솔루션의 성능이 내 것보다 뛰어납니다 (이전). foreach가 배열을 통과하는 가장 빠른 방법으로 권장되기 때문에 그렇지 않다고 생각합니다.
podperson

7

이 함수는 다음을 처리 할 수 ​​있습니다.

  • 인덱스에 구멍이있는 배열 (예 : 1,2,4,5,8,10)
  • "0x"키를 가진 배열 : 예 : 키 '08'은 연관적이고 키 '8'은 순차적입니다.

아이디어는 간단합니다. 키 중 하나가 정수가 아닌 경우 연관 배열이며, 그렇지 않으면 순차적입니다.

function is_asso($a){
    foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
    return FALSE;
}

1
"키 중 하나가 정수가 아닌 경우 연관 배열입니다. 그렇지 않으면 순차적입니다" -허? 아니요, 이것은 단순히 잘못입니다. "연관"배열을 구성하는 것에 대한 논쟁의 여지가 있지만 "순차적"의 의미는 분명하고, 모든 키가 숫자 인 것과 동일하지는 않습니다.
Mark Amery

키 중 하나가 정수가 아닌 경우 본질적으로 연관성이 있지만 키가 0-길이 (배열)-1에서 시작하는 경우에만 순차적입니다. 그러나 모든 키의 번호가 매겨져 있지만 숫자가 될 수는 있지만 NUMERIC입니다. 또는 순차적 배열이 필요한 많은 배열 함수에서 작동하지 않을 수 있습니다. array_values ​​(array)를 실행하여 구멍이있는 숫자 형 배열을 순차적으로 변환하면 순차적으로 변환됩니다.
geilt

7

이 질문에 대한 두 가지 대중적인 접근 방식을 array_values()사용했습니다 key(). 어느 것이 더 빠른지 알아보기 위해 작은 프로그램을 작성했습니다.

$arrays = Array(
  'Array #1' => Array(1, 2, 3, 54, 23, 212, 123, 1, 1),
  'Array #2' => Array("Stack", 1.5, 20, Array(3.4)),
  'Array #3' => Array(1 => 4, 2 => 2),
  'Array #4' => Array(3.0, "2", 3000, "Stack", 5 => "4"),
  'Array #5' => Array("3" => 4, "2" => 2),
  'Array #6' => Array("0" => "One", 1.0 => "Two", 2 => "Three"),
  'Array #7' => Array(3 => "asdf", 4 => "asdf"),
  'Array #8' => Array("apple" => 1, "orange" => 2),
);

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

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

// Method #1
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
  foreach ($arrays as $array) {
    $dummy = is_indexed_array_1($array);
  }
}
$end = microtime(true);
echo "Time taken with method #1 = ".round(($end-$start)*1000.0,3)."ms\n";

// Method #2
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
  foreach ($arrays as $array) {
    $dummy = is_indexed_array_2($array);
  }
}
$end = microtime(true);
echo "Time taken with method #1 = ".round(($end-$start)*1000.0,3)."ms\n";

CentOS에서 PHP 5.2의 프로그램 출력은 다음과 같습니다.

방법 # 1 = 10.745ms로 걸린
시간 방법 # 2 = 18.239ms로 걸린 시간

PHP 5.3의 결과는 비슷한 결과를 냈습니다. 분명히 사용하는 array_values()것이 훨씬 빠릅니다.


나쁜 기준. 큰 배열을 테스트하지 않았습니다. 내 컴퓨터에서 10K + 요소로 시작하는 방법 # 2가 더 빠릅니다. 함께 시도$arrays = Array( 'Array #1' => range(0, 50000), );
nonsensei

7

이에 접근하는 한 가지 방법은 피기 백 (piggyback)하는 것입니다 json_encode.이 방법은 올바른 JSON을 출력하기 위해 연관 배열과 인덱스 배열을 구별하는 자체 내부 방법이 이미 있습니다.

인코딩 후 반환 된 첫 번째 문자가 {(연관 배열) 또는 [(인덱싱 배열) 인지 확인하여이 작업을 수행 할 수 있습니다 .

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}

내 의견으로는 ksort ()가 필요하지 않습니다. 이 솔루션은 작동하지만 $ arr이 null인지 여부와 json_encode가 실패하면 try / catch를 테스트해야합니다. + $ arr이 크면 실제로 최적이 아닙니다.
lucbonnin

7

이미 많은 답변이 있지만 Laravel이 Arr 클래스 내에서 사용하는 방법은 다음과 같습니다.

/**
 * Determines if an array is associative.
 *
 * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
 *
 * @param  array  $array
 * @return bool
 */
public static function isAssoc(array $array)
{
    $keys = array_keys($array);

    return array_keys($keys) !== $keys;
}

출처 : https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php


1
@Casey array_keys($keys)는 원래 배열과 길이가 같은 일련의 숫자 배열 (0 ... X)을 반환합니다. 예를 들어 array_keys(["a", "b", "c"]) = [0, 1, 2]; array_keys([0, 1, 2]) = [0, 1, 2](순차 배열이므로 [0, 1, 2] !== [0, 1, 2]). 또 다른 예 : array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"]; array_keys(["a", "b", "c"]) = [0, 1, 2](왜냐하면 연관 배열입니다 ["a", "b", "c"] !== [0, 1, 2]). 그것이 분명하기를 희망합니다 (적어도 나를 위해 주석으로 광범위하게 설명하기는 어렵습니다)
valepu

이 알고리즘은 미치며 쉽고 이해하기 쉽습니다.
Benyi

연관 행의 순차 배열이있는 경우에는 작동하지 않습니다.
lucbonnin

5
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

빠르고 간결하며 메모리 효율적입니다. 비싼 비교, 함수 호출 또는 배열 복사가 없습니다.


4

xarray PHP 확장 을 사용하여

이 작업은 매우 빠르게 수행 할 수 있습니다 (PHP 5.6에서는 약 30 배 이상 빠름).

if (array_is_indexed($array)) {  }

또는:

if (array_is_assoc($array)) {  }

3

이 거대한 대기열에 대한 답변을 추가하는 것이 의미가 없다는 것을 알고 있지만 값을 복제 할 필요가없는 읽을 수있는 O (n) 솔루션이 있습니다.

function isNumericArray($array) {
    $count = count($array);
    for ($i = 0; $i < $count; $i++) {
        if (!isset($array[$i])) {
            return FALSE;
        }
    }
    return TRUE;
}

그들은 모두 숫자 경우 오히려 키를 확인 당신보다 반복 처리의 키에 걸쳐 볼 것이다 숫자 배열이있을 수 있는지가 존재합니다.


한 가지 더. 형식의 배열 [1,2,null,4]이 실패하지만 올바른 배열입니다. 난에서 일부 개선을 추가 한 있도록 stackoverflow.com/a/25206156/501831 추가로 array_key_exists확인)
lazycommit

-1; @lazycommit에서 지적한 것처럼 isset()값이 설정 null되었지만가 인 경우 false를 반환하므로 잘못된 도구 입니다.
Mark Amery

3

내 해결책 :

function isAssociative(array $array)
{
    return array_keys(array_merge($array)) !== range(0, count($array) - 1);
}

array_merge단일 배열에서 모든 integer키 를 다시 색인화 하지만 다른 키 는 다시 색인화 하지 않습니다. 예를 들면 다음과 같습니다.

array_merge([1 => 'One', 3 => 'Three', 'two' => 'Two', 6 => 'Six']);

// This will returns [0 => 'One', 1 => 'Three', 'two' => 'Two', 2 => 'Six']

따라서 목록 (비 연관 배열)이 만들어 지면 ['a', 'b', 'c']값이 제거 된 unset($a[1])다음 array_merge호출되고 0부터 시작하여 목록이 다시 색인화됩니다.


-1; 이것은 O(n)사용 된 추가 메모리에 있으며 (만큼 많은 요소로 여러 개의 새로운 배열을 만들었으므로 $array) 대답은 질문 된 질문의 모호성을 해결하지 않으며 목록 / 비 연관 배열을 정의하는 방법을 정확하게 설명하지 않으며 심지어 이 중 어느 것도 사실이 아니면 이미 게시 된 다른 답변과 비교하여 어떤 가치가 추가되는지 확실하지 않습니다.
Mark Amery

3

일부 로컬 벤치마킹, 디버깅, 컴파일러 프로빙, ​​프로파일 링 및 3v4l.org를 남용하여 더 많은 버전에서 벤치 마크하고 (예, 중지하라는 경고가 표시됨) 찾을 수있는 모든 변형과 비교 ...

나는 다른 모든 평균 사례 시나리오보다 최악의 결과를 가져 오는 유기적으로 파생 된 최상의 평균 최악의 시나리오 연관 배열 테스트 기능을 제공합니다 .

/**
 * Tests if an array is an associative array.
 *
 * @param array $array An array to test.
 * @return boolean True if the array is associative, otherwise false.
 */
function is_assoc(array &$arr) {
    // don't try to check non-arrays or empty arrays
    if (FALSE === is_array($arr) || 0 === ($l = count($arr))) {
        return false;
    }

    // shortcut by guessing at the beginning
    reset($arr);
    if (key($arr) !== 0) {
        return true;
    }

    // shortcut by guessing at the end
    end($arr);
    if (key($arr) !== $l-1) {
        return true;
    }

    // rely on php to optimize test by reference or fast compare
    return array_values($arr) !== $arr;
}

에서 https://3v4l.org/rkieX :

<?php

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

// method_2 was DQ; did not actually work

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

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

// guessing
function method_5(Array &$arr) {
    global $METHOD_5_KEY;
    $i = 0;
    $l = count($arr)-1;

    end($arr);
    if ( key($arr) !== $l )
        return FALSE;

    reset($arr);
    do {
        if ( $i !== key($arr) )
            return FALSE;
        ++$i;
        next($arr);
    } while ($i < $l);
    return TRUE;
}

// naieve
function method_6(Array &$arr) {
    $i = 0;
    $l = count($arr);
    do {
        if ( NULL === @$arr[$i] )
            return FALSE;
        ++$i;
    } while ($i < $l);
    return TRUE;
}

// deep reference reliance
function method_7(Array &$arr) {
    return array_keys(array_values($arr)) === array_keys($arr);
}


// organic (guessing + array_values)
function method_8(Array &$arr) {
    reset($arr);
    if ( key($arr) !== 0 )
        return FALSE;

    end($arr);
    if ( key($arr) !== count($arr)-1 )
        return FALSE;

    return array_values($arr) === $arr;
}

function benchmark(Array &$methods, Array &$target, $expected){    
    foreach($methods as $method){
        $start = microtime(true);
        for ($i = 0; $i < 2000; ++$i) {
            //$dummy = call_user_func($method, $target);
            if ( $method($target) !== $expected ) {
                echo "Method $method is disqualified for returning an incorrect result.\n";
                unset($methods[array_search($method,$methods,true)]);
                $i = 0;
                break;
            }
        }
        if ( $i != 0 ) {
            $end = microtime(true);
            echo "Time taken with $method = ".round(($end-$start)*1000.0,3)."ms\n";
        }
    }
}



$true_targets = [
    'Giant array' => range(0, 500),
    'Tiny array' => range(0, 20),
];


$g = range(0,10);
unset($g[0]);

$false_targets = [
    'Large array 1' => range(0, 100) + ['a'=>'a'] + range(101, 200),
    'Large array 2' => ['a'=>'a'] + range(0, 200),
    'Tiny array' => range(0, 10) + ['a'=>'a'] + range(11, 20),
    'Gotcha array' => $g,
];

$methods = [
    'method_1',
    'method_3',
    'method_4',
    'method_5',
    'method_6',
    'method_7',
    'method_8'
];


foreach($false_targets as $targetName => $target){
    echo "==== Benchmark using $targetName expecing FALSE ====\n";
    benchmark($methods, $target, false);
    echo "\n";
}
foreach($true_targets as $targetName => $target){
    echo "==== Benchmark using $targetName expecting TRUE ====\n";
    benchmark($methods, $target, true);
    echo "\n";
}

2

내가 사용하는 방법은 다음과 같습니다.

function is_associative ( $a )
{
    return in_array(false, array_map('is_numeric', array_keys($a)));
}

assert( true === is_associative(array(1, 2, 3, 4)) );

assert( false === is_associative(array('foo' => 'bar', 'bar' => 'baz')) );

assert( false === is_associative(array(1, 2, 3, 'foo' => 'bar')) );

이것은 다음과 같은 특별한 경우를 설명하지 않습니다.

$a = array( 1, 2, 3, 4 );

unset($a[1]);

assert( true === is_associative($a) );

죄송합니다. 도와 드릴 수 없습니다. 불필요 한 사본을 만들지 않기 때문에 적절한 크기의 배열에 대해서도 다소 성능이 좋습니다. 파이썬과 루비를 작성하는 것이 훨씬 더 좋은 것은이 작은 것입니다 : : P


2
<?php

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

function is_assoc($array) {
    return count(array_filter(array_keys($array), 'is_string')) == count($array);
}

?>

가장 많은 점수를 얻은이 두 예제는 다음과 같은 배열에서 올바르게 작동하지 않습니다. $array = array('foo' => 'bar', 1)


+1 귀하의 is_list () 는 IMO가 가장 좋습니다. 어떤 사람들은 시간과 공간의 복잡성, 그리고 네이티브 대 PHP 스크립트 기능에 대한 실마리가 없습니다.
e2-e4

2

이것도 작동합니다 ( demo ) :

function array_has_numeric_keys_only(array $array)
{
    try {
        SplFixedArray::fromArray($array, true);
    } catch (InvalidArgumentException $e) {
        return false;
    }
    return true;
}

이 답변의 주요 요점은 SplFixedArray이러한 종류의 테스트에 예외를 사용하도록 장려하지 말고 알려주는 것 입니다.


2

스칼라 배열의 정의는 응용 프로그램마다 다를 것이라고 생각합니다. 즉, 일부 응용 프로그램은 스칼라 배열의 자격에 대해보다 엄격한 의미를 요구하고 일부 응용 프로그램은 더 느슨한 의미를 요구합니다.

아래에는 다양한 엄격 성의 세 가지 방법이 나와 있습니다.

<?php
/**
 * Since PHP stores all arrays as associative internally, there is no proper
 * definition of a scalar array.
 * 
 * As such, developers are likely to have varying definitions of scalar array,
 * based on their application needs.
 * 
 * In this file, I present 3 increasingly strict methods of determining if an
 * array is scalar.
 * 
 * @author David Farrell <DavidPFarrell@gmail.com>
 */

/**
 * isArrayWithOnlyIntKeys defines a scalar array as containing
 * only integer keys.
 * 
 * If you are explicitly setting integer keys on an array, you
 * may need this function to determine scalar-ness.
 * 
 * @param array $a
 * @return boolean
 */ 
function isArrayWithOnlyIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    foreach ($a as $k => $v)
        if (!is_int($k))
            return false;
    return true;
}

/**
 * isArrayWithOnlyAscendingIntKeys defines a scalar array as
 * containing only integer keys in ascending (but not necessarily
 * sequential) order.
 * 
 * If you are performing pushes, pops, and unsets on your array,
 * you may need this function to determine scalar-ness.
 * 
 * @param array $a
 * @return boolean
 */ 
function isArrayWithOnlyAscendingIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    $prev = null;
    foreach ($a as $k => $v)
    {
        if (!is_int($k) || (null !== $prev && $k <= $prev))
            return false;
        $prev = $k;
    }
    return true;
}

/**
 * isArrayWithOnlyZeroBasedSequentialIntKeys defines a scalar array
 * as containing only integer keys in sequential, ascending order,
 * starting from 0.
 * 
 * If you are only performing operations on your array that are
 * guaranteed to either maintain consistent key values, or that
 * re-base the keys for consistency, then you can use this function.
 * 
 * @param array $a
 * @return boolean
 */
function isArrayWithOnlyZeroBasedSequentialIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    $i = 0;
    foreach ($a as $k => $v)
        if ($i++ !== $k)
            return false;
    return true;
}

2

소스 에서 하나 더 빨리 . json_encode(및 bson_encode)의 인코딩을 적합합니다 . 자바 스크립트 배열 준수도 있습니다.

function isSequential($value){
    if(is_array($value) || ($value instanceof \Countable && $value instanceof \ArrayAccess)){
        for ($i = count($value) - 1; $i >= 0; $i--) {
            if (!isset($value[$i]) && !array_key_exists($i, $value)) {
                return false;
            }
        }
        return true;
    } else {
        throw new \InvalidArgumentException(
            sprintf('Data type "%s" is not supported by method %s', gettype($value), __METHOD__)
        );
    }
}

1
isset그리고 array_key_exists? 후자는 충분하지 않습니까?
mcfedr 2016 년

@mcfedr 그렇습니다 isset(). 여기서 확인하는 것이 완전히 중복됩니다.
Mark Amery

성능상의 이유로 @mcfedr, @ mark-amery. isset()보다 빠릅니다 array_key_exists(). ilia.ws/archives/…
lazycommit

@lazycommit 배열에 따라 달라 지겠지만 nulls 가 많은 배열을 가질 가능성이 아니라 성능 차이가있을 정도로 배열이 크지 않을 수도 있습니다. 두 가지 검사를 모두 사용하여
mcfedr

2
당신이 맞는 것인지 확인해야하는 경우 json_encode, 당신은 단순히 의해 반환 된 문자열의 첫 번째 기호를 확인할 수 있습니다 json_encode($your_arr)그것은 여부 - [또는 {;-)
PILAT

2

이것이 해결책이 될 수 있습니까?

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

경고는 배열 커서가 재설정된다는 것이 분명하지만 배열이 횡단되거나 사용되기 전에 함수가 사용된다고 말할 수 있습니다.


이 기능은 반환 거짓 모두 array("a", "b")array("a", "b" => "B")첫 번째 키 그것은 단지 검사 등. BTW is_long는의 별칭입니다is_int .
Pang

1
솔직히 말해서 이것이 대부분의 경우에 매우 효과적이며 대안보다 훨씬 효율적이라고 생각합니다. 이 방법의 결과를 이해하고 그것이 당신에게 효과가 있다는 것을 알고 있다면, 그것은 최선의 선택 일 것입니다.
Gershom

이것은 단순히 잘못입니다. 첫 번째 키만 봅니다.
Mark Amery

@MarkAmery 문제는 구별하는 방법을 묻는 순수 에서 순차 배열 순수하게 연관 배열을. 이 답변은 정확히 그렇게하며 가장 효율적입니다. 혼합 된 배열에 대해 정의되지 않은 동작을 갖는 것은 질문의 맥락에서 완벽하게 좋습니다. +1
Tobia

@Tobia 나는 대부분의 사람들 [7 => 'foo', 2 => 'bar']이 부분적으로 "순수하게"순차가 아닌 "혼합"배열로 분류하는 것에 동의하지 않을 것이라고 생각한다 . 그것은 분명히 나에게 단어를 잘못 사용하는 것처럼 보입니다.
Mark Amery

2

여기의 많은 솔루션은 우아하고 예쁘지 만 확장 성이 좋지 않으며 메모리를 많이 사용하거나 CPU를 많이 사용합니다. 대부분이 솔루션의 두 가지 측면에서이 솔루션으로 메모리에 2 개의 새로운 데이터 포인트를 생성하고 있습니다. 어레이가 클수록 사용 된 프로세스와 메모리가 더 어려워지고 단락 평가의 이점을 잃게됩니다. 몇 가지 다른 아이디어로 테스트했습니다. 비용이 많이 들기 때문에 array_key_exists를 피하려고 시도하고 비교할 새로운 대용량 데이터 세트를 작성하지 마십시오. 배열이 순차적인지 알 수있는 간단한 방법이라고 생각합니다.

public function is_sequential( $arr = [] ){
    if( !is_array( $arr ) || empty( $arr ) ) return false;

    $i = 0;

    $total = count( $arr );

    foreach( $arr as $key => $value ) if( $key !== $i++ ) return false;

    return true;
}

기본 배열에서 단일 카운트를 실행하고 단일 정수를 저장합니다. 그런 다음 배열을 반복하고 카운터를 반복하는 동안 정확히 일치하는지 확인하십시오. 1부터 세어야합니다. 실패하면 단락되어 거짓 일 때 성능이 향상됩니다.

원래 for 루프로이 작업을 수행하고 isset ($ arr [$ i])을 확인했지만 array_key_exists가 필요한 null 키는 감지하지 못하며 속도에 사용하는 최악의 함수입니다.

정수 크기를 초과하지 않는 반복자와 함께 점검하기 위해 foreach를 통해 변수를 지속적으로 업데이트하십시오 .PHP는 메모리 최적화, 캐싱 및 가비지 수집 기능을 내장하여 리소스 사용량을 최소화합니다.

또한 foreach에서 array_keys를 사용하는 것은 $ key => $ value를 실행하고 키를 확인할 수있을 때 어리석은 것이라고 주장합니다. 새로운 데이터 포인트를 만드는 이유는 무엇입니까? 배열 키를 추상화하면 즉시 더 많은 메모리를 소비했습니다.


1

답변이 이미 제공되었지만 성능에 대한 정보가 너무 많습니다. foreach 방법이 가장 빠르다는 것을 보여주는이 작은 벤치 마크 스크립트를 작성했습니다.

면책 조항 : 다음 답변은 다른 답변에서 복사하여 붙여 넣었습니다.

<?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";
}

결과 :

==== 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

1

또는 당신은 이것을 사용할 수 있습니다 :

Arr::isAssoc($array)

배열에 숫자가 아닌 키 가 포함되어 있는지 확인 하거나

Arr:isAssoc($array, true)

배열 이 엄격한 순서 인지 확인합니다 (자동 생성 된 int 키 0 ~ n-1 포함 )

라이브러리를 사용 합니다 .


0

PHP가 내장되어 있지 않으면 O (n) 미만으로 모든 키를 열거하고 정수 유형을 검사하여 PHP를 수행 할 수 없습니다. 실제로 구멍이 없는지 확인하고 알고리즘이 다음과 같이 보일 수 있습니다.

for i in 0 to len(your_array):
    if not defined(your-array[i]):
        # this is not an array array, it's an associative array :)

그런데 왜 귀찮게? 배열이 원하는 유형이라고 가정하십시오. 그렇지 않다면, 그것은 당신의 얼굴에 날려 버릴 것입니다-그것은 당신을위한 동적 프로그래밍입니다! 코드를 테스트하면 모든 것이 잘 될 것입니다 ...


1
일반적으로 배열이 원하는 유형이라고 가정하면 갈 수 있습니다. 그러나 제 경우에는 다차원 배열을 반복하고 주어진 노드의 배열 유형에 따라 출력 형식을 지정합니다.
Wilco

0

배열의 키와 배열의 array_values ​​() 결과의 키의 차이를 비교합니다. 이는 항상 정수 인덱스가있는 배열입니다. 키가 동일하면 연관 배열이 아닙니다.

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}

-1; 이것은 사용하는 O(n)추가 메모리를 $array갖는 n항목을 작성하고 (someboolean) ? false : true대신하여 !someboolean끔찍한이고 지나치게 상세한.
Mark Amery
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.