programing

PHP 배열이 연관성이 있는지 순차적인지 확인하는 방법

newsource 2022. 10. 27. 21:53

PHP 배열이 연관성이 있는지 순차적인지 확인하는 방법

PHP는 모든 어레이를 연관지을 수 있으므로 내장 함수는 없습니다.어레이가 "리스트"인지 확인하는 매우 효율적인 방법(0부터 시작하는 숫자 키만 포함)을 추천할 수 있습니까?

기본적으로는 다음과 같은 것을 구별할 수 있어야 합니다.

$sequentialArray = [
    'apple', 'orange', 'tomato', 'carrot'
];

또, 이하와 같이 됩니다.

$assocArray = [
    'fruit1' => 'apple',
    'fruit2' => 'orange',
    'veg1' => 'tomato',
    'veg2' => 'carrot'
];

완전히 동일하지 않은 두 가지 질문을 했습니다.

  • 먼저 어레이에 숫자 키만 있는지 확인하는 방법
  • 두 번째로 어레이에 0부터 시작하는 순차적 숫자 키가 있는지 확인하는 방법

이러한 행동 중 실제로 필요한 것이 무엇인지 생각해 보십시오.(어느 쪽이든 목적에 맞는 행동일 수 있습니다.)

첫 번째 질문(단순히 모든 키가 숫자인지 확인)은 캡틴 KURO가 잘 대답했습니다.

두 번째 질문(배열이 제로 인덱스 및 시퀀셜인지 확인)에는 다음 함수를 사용할 수 있습니다.

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

어레이에 정수 이외의 키가 있는지 여부를 확인하는 방법(어레이가 순차적으로 인덱스화되는지 제로 인덱스화되지 않았는지 아님)을 확인하는 방법:

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

키가 개 있는 는, 「」입니다.$array연관 배열로 간주됩니다.

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

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

이 질문의 많은 코멘트는 배열이 PHP에서 어떻게 작동하는지 이해하지 못합니다.어레이 매뉴얼에서 다음을 참조해 주세요.

키는 정수 또는 문자열 중 하나입니다.키가 정수의 표준 표현일 경우 다음과 같이 해석됩니다(즉, "8"은 8로 해석되고 "08"은 "08"로 해석됩니다).키의 플로트는 정수로 잘립니다.인덱싱된 배열 및 연관 배열 유형은 정수 및 문자열 인덱스를 모두 포함할 수 있는 PHP의 동일한 유형입니다.

즉, 배열 키 8은 항상 (사일런트하게) 정수 8로 변환되기 때문에 배열 키 8은 존재하지 않습니다.따라서 정수와 숫자 문자열을 구분하려고 할 필요가 없습니다.

어레이의 일부(array_keys()처럼) 또는 모든 복사본을 만들지 않고 어레이에서 정수 이외의 키를 확인하는 가장 효율적인 방법을 원하는 경우:

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);

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

OP에 기재된 바와 같이:

PHP는 모든 어레이를 연관성으로 취급합니다.

배열이 연관성이 있는지 확인하는 함수를 쓰는 것은 매우 합리적이지 않습니다(IMHO).우선 PHP 어레이의 키란 무엇입니까?

정수 또는 문자열 중 하나입니다.

즉, 다음의 3가지 경우가 있습니다.

  • 케이스 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;
}

다음과 같습니다.

  • 값이 배열이 아닌 경우 3가지 함수는 모두 false를 반환합니다.
  • 값이 빈 배열일 경우 3가지 함수가 모두 true를 반환합니다.
    (이것은 정의상 "빈 집합은 모든 요소A 속하기 때문모든 집합 A의 하위 집합"과 같다).
  • 값이 비어 있지 않은 배열인 경우 정확히 1개의 함수true를 반환합니다.

이제 어레이가 우리 모두에게 익숙한 "정품" 어레이가 되기 위해서는 다음과 같은 의미가 있습니다.

  • 키는 모두 숫자/정수입니다.
  • 키는 순차적입니다(1단계까지 증가).
  • 키는 0부터 시작합니다.

아래 기능으로 확인할 수 있습니다.

케이스 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")문자열입니다. 틀렸습니다.여기 있는 문서:

유효한 정수를 포함하는 문자열이 정수 형식으로 캐스팅됩니다.예: 키 "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비트 플랫폼의 최대값은 보통 약 9E18입니다.단, Windows는 항상 32비트입니다.PHP는 부호 없는 정수를 지원하지 않습니다.

따라서 이 어레이의 키는 플랫폼에 따라 정수가 될 도 있고 아닐 수도 있습니다.

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

더 나쁜 것은 정수가 2 = 2,480,483,648 경계31 근처에 있으면 PHP가 버그가 되는 경향이 있다는 것입니다(버그 51430,버그 52899 참조).예를 들어 로컬 환경(Windows 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"
}

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

속도:

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

메모리 측면:

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

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

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

이것은, 키(시퀀셜 배열의 경우는 항상 0, 1, 2 등)와 키의 키(항상 0, 1, 2 등)를 비교하기 때문에 기능합니다.

Laravel은 이 방법을 사용합니다.

PHP 8.1은 어레이가 이러한 의미론을 가진 목록인지 아닌지를 판단하기 위한 내장 함수를 추가합니다.함수는 다음과 같습니다.

$list = ["a", "b", "c"];

array_is_list($list); // true

$notAList = [1 => "a", 2 => "b", 3 => "c"];

array_is_list($notAList); // false

$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

array_is_list($alsoNotAList); // false

언급

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

다요.array_keys($obj) !== range(0, count($obj) - 1) ★★★★★★★★★★★★★★★★★」array_values($arr) !== $arr(두 번째 어레이는 첫 번째 어레이보다 저렴하지만 서로 듀얼이지만) 매우 큰 어레이에서는 둘 다 실패합니다.

그 이유는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★★★★★★ 。

마지막으로, 이 페이지의 「솔루션」보다 「고급」이 훨씬 적은 것 같지만, 실제로는 훨씬 효율적입니다.거의 모든 관련 어레이가 즉시 인식됩니다.인덱스된 어레이만 완전히 검사됩니다.상기의 방법에서는 인덱스된 어레이를 완전히 검사할 뿐만 아니라 중복됩니다.

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

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를 실행하면 짧아질 수 있지만(코드는 적어집니다), 콜을 발신하면 백그라운드에서 무슨 일이 일어나는지 주의해 주세요.네, 다른 솔루션보다 더 많은 (눈에 보이는) 문장이 있지만, 중요한 것은 그게 아닙니다.
  • 시기적절:데이터나 키의 복사/해동에도 시간이 걸리는 것 외에, 이 솔루션은 Forech를 실행하는 것보다 효율적입니다.포어치는 표기법이 짧기 때문에 일부에서는 더 효율적인 것처럼 보일 수 있지만, 백그라운드에서는 리셋, 키 및 루프를 실행하기 위한 다음 호출도 합니다.다만, 종료 조건을 체크하기 위해서도 유효하게 콜 합니다.이 경우는 정수 체크와의 조합에 의해 회피됩니다.

배열 키는 정수 또는 문자열만 사용할 수 있으며 "1"과 같은 엄밀한 숫자 문자열("01"이 아님)은 정수로 변환됩니다.따라서 배열이 순차적으로 수행되도록 하려면 정수 키를 확인하는 작업만 필요합니다.당연히 is_indexed_array가 false를 반환하는 경우 어레이는 연관성이 있다고 볼 수 있습니다.내가 '보였다'고 말하는 이유는 사실 그들 모두가 그랬기 때문이다.

여기 또 다른 단순하지만 강력한 논리가 있습니다(그 내부 메커니즘의 Laravel 프레임워크에서도 사용됩니다).

/**
 * Determines if an array is associative.
 * @param  array  $array
 * @return bool
 */
function isAssoc(array $array)
{
    $keys = array_keys($array);

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

하는 한 으로 하는 것입니다.json_encode에는, 적절한 JSON을 출력하기 위해서, 관련 배열과 인덱스 배열을 구별하는 독자적인 내부 방법이 이미 있습니다.

후되는 첫 번째 가 '아까'인지할 수 있습니다.{ 어레이) a(어소시에이션 어레이)[(일부러)

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

빠르고 간결하며 메모리 효율이 뛰어납니다.값비싼 비교, 함수 호출, 어레이 복사 불필요.

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

  • 인덱스에 구멍이 있는 배열(예: 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;
}

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

/**
 * 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

는 이 두 했다. 는 '사용하는 방법'이다. 하나는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";

Cent의 PHP 5.2 프로그램 출력OS는 다음과 같습니다.

1= #1로 소요된 시간 = 10.745ms
2= #에서 소요된 시간 = 18.239ms

PHP 5.3은 PHP 5.3입니다.분명히 사용하고 있다array_values()훨씬 더 빠릅니다.

대부분의 답변은 시간/공간의 복잡성이 최적이 아니거나 시멘틱스가 변화하고 있습니다.다음으로 가장 빠르고 기능적으로 올바른 솔루션을 제시하겠습니다.

function is_sequential_array(Array &$a) {
    $n = count($a);
    for($i=0; $i<$n; $i++) {
        if(!array_key_exists($i, $a)) {
            return false;
        }
    }
    return true;
}

이 답변에는 다른 답변에 비해 다음과 같은 이점이 있습니다.

  1. 간간잡의 O(1)서는 많은 을 사용합니다).O(n)★★★★★★★★★★★★★★★★★★」
  2. 키에 균등성을 적용하지 않음(불필요하고 비용이 많이 드는 작업)
  3. 입력 어레이를 불변으로 취급합니다(많은 응답은 변환 함수를 적용하여 암묵적으로 복사본을 만들었습니다).
  4. " " " 를 사용합니다.array_key_existsissetissetis null'은 아니다.
  5. 는 " " " 입니다.O(n)서는, 회답이, 베스트 의 시간 time complexity)를 있습니다).O(n))

로컬 벤치마킹, 디버깅, 컴파일러 검색, 프로파일링 및 3v4l.org을 악용하여 여러 버전을 벤치마킹한 후(예, 중지하라는 경고가 표시됨) 발견된 모든 변형과 비교합니다.

유기적으로 도출된 Best-Average-Worst-Case 시나리오 어소시에이션 어레이 테스트 기능을 소개합니다. 기능은 다른 모든 평균 케이스 시나리오와 거의 같거나 더 우수합니다.

/**
 * 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";
}

이 거대한 큐에 답을 추가하는 것이 다소 무의미하다는 것을 알지만, 여기 값을 복제할 필요가 없는 읽기 쉬운 O(n) 솔루션이 있습니다.

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

키가 모두 숫자인지 확인하는 대신 숫자 배열에 해당하는 를 반복하여 키가 존재하는지 확인합니다.

xarray PHP 확장 사용

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

if (array_is_indexed($array)) {  }

또는 다음 중 하나를 선택합니다.

if (array_is_assoc($array)) {  }

이 솔루션의 대부분은 우아하고 아름답지만 확장성이 뛰어나지 않고 메모리나 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 loop을 사용하여 isset($ar[$i])을 체크했지만, 이것은 array_key_exists를 필요로 하는 늘키를 검출하지 않습니다.이것은 속도를 높이기 위해 사용하는 최악의 함수입니다.

Foreach를 통해 변수를 지속적으로 업데이트하여 정수 크기를 넘지 않는 반복기와 함께 PHP는 내장된 메모리 최적화, 캐시 및 가비지 컬렉션을 사용하여 리소스 사용량을 매우 낮게 유지합니다.

또한 $key = > $value를 실행하여 키를 확인할 수 있다면 foreach에서 array_keys를 사용하는 것은 어리석은 일이라고 주장하겠습니다.새로운 데이터 포인트를 작성하는 이유어레이 키를 추상화하면, 곧바로 메모리를 소비하게 됩니다.

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

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

<?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)

이것도 동작합니다(데모).

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

은 '알리다'의 입니다.SplFixedArray이러한 종류의 테스트에 예외를 사용하지 않도록 권장합니다.

스칼라 배열의 정의는 어플리케이션에 따라 다를 것입니다.즉, 스칼라 어레이로서 무엇이 적합한지에 대한 보다 엄격한 인식이 필요한 애플리케이션도 있고, 보다 느슨한 인식이 필요한 애플리케이션도 있습니다.

아래는 엄격함을 변화시키는 세 가지 방법을 제시하겠습니다.

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

소스로부터 한 번 더 빨리.적합 부호화json_encode (그리고)bson_encode Array javascript Array도

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__)
        );
    }
}

이게 해결책일까요?

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

주의할 점은 어레이 커서가 리셋된다는 것입니다만, 이 기능은 어레이를 통과하거나 사용하기 전에 이미 사용되고 있을 가능성이 있습니다.

솔루션:

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

array_merge에서 모든 1개의 1개 어레이를 .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호출되면 이 01에서 됩니다.

답은 이미 나왔는데 퍼포먼스에 대한 잘못된 정보가 너무 많아요.저는 이 작은 벤치마크 대본을 작성했습니다. 포어치 방식이 가장 빠르다는 것을 보여줍니다.

면책사항: 다음 방법은 다른 답변에서 복사하여 붙여넣은 것입니다.

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

언급URL : https://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential