PHP 배열이 연관 또는 순차인지 확인하는 방법은 무엇입니까?
PHP는 모든 배열을 연관성으로 취급하므로 내장 함수가 없습니다. 누구나 배열에 숫자 키만 포함되어 있는지 확인하는 상당히 효율적인 방법을 추천 할 수 있습니까?
기본적으로 이것을 구분할 수 있기를 원합니다.
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
이:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
똑같지 않은 두 가지 질문을했습니다.
- 첫째, 배열에 숫자 키만 있는지 확인하는 방법
- 둘째, 배열에 0부터 시작하는 순차적 숫자 키 가 있는지 확인하는 방법
실제로 필요한 행동을 고려하십시오. (둘 중 하나가 귀하의 목적에 맞을 수 있습니다.)
첫 번째 질문 (단순히 모든 키가 숫자인지 확인)은 Captain kurO가 잘 대답합니다 .
두 번째 질문 (배열이 제로 인덱싱되고 순차적인지 확인)의 경우 다음 함수를 사용할 수 있습니다.
function isAssoc(array $arr)
{
if (array() === $arr) return false;
return array_keys($arr) !== range(0, count($arr) - 1);
}
var_dump(isAssoc(array('a', 'b', 'c'))); // false
var_dump(isAssoc(array("0" => 'a', "1" => 'b', "2" => 'c'))); // false
var_dump(isAssoc(array("1" => 'a', "0" => 'b', "2" => 'c'))); // true
var_dump(isAssoc(array("a" => 'a', "b" => 'b', "c" => 'c'))); // true
단순히 배열에 정수가 아닌 키가 있는지 확인하려면 (배열이 순차적으로 인덱싱되었는지 0 인덱싱되었는지 여부가 아님) :
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로 (자동으로) 변환되기 때문에 존재하지 않습니다. 따라서 정수와 숫자 문자열을 구별하려고 할 필요가 없습니다.
배열의 일부 (예 : 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을 배열 키로 사용하려고하면 ""로 자동 변환 됨).
으로 영업에 의해 진술 :
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;
}
다음과 같습니다.
- 값이면 배열이 아닌 , 3 개 함수 반환 거짓 .
- 값이 빈 배열 이면 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")
A는 문자열 , 당신은 잘못입니다 . 여기 문서 에서 :
유효한 정수를 포함하는 문자열은 정수 유형으로 캐스트됩니다. 예를 들어 키 "8"은 실제로 8 아래에 저장됩니다. 반면에 "08"은 유효한 십진 정수가 아니기 때문에 캐스트되지 않습니다.
예를 들어 이러한 배열의 키는 정수입니다 .
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 31 = 2,147,483,648 경계 근처에 있으면 PHP가 버그 가있는 경향이 있습니다 ( bug 51430 , bug 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
속도 측면 :
function isAssoc($array)
{
return ($array !== array_values($array));
}
메모리 측면 :
function isAssoc($array)
{
$array = array_keys($array); return ($array !== array_keys($array));
}
function checkAssoc($array){
return ctype_digit( implode('', array_keys($array) ) );
}
실제로 가장 효율적인 방법은 다음과 같습니다.
function is_assoc($array){
$keys = array_keys($array);
return $keys !== array_keys($keys);
}
이것은 (순차적 인 배열에 대해 항상있는 0,1,2 등)의 키를 비교하기 때문에 작동 (것 키의 키에 항상 0, 1, 2 등이 될).
난 둘 다 사용했습니다 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
블록 에서 간단히 반환 할 수 있습니다 .
마지막으로,이 페이지에있는 많은 "솔루션"보다 "우아함"이 훨씬 덜할 수 있지만 실제로는 훨씬 더 효율적입니다. 거의 모든 연관 배열이 즉시 감지됩니다. 인덱싱 된 배열 만 철저하게 검사되며 위에서 설명한 방법은 인덱싱 된 배열을 철저히 검사 할뿐만 아니라 복제합니다.
다음 두 함수가 '배열이 연관성인지 숫자인지'를 확인하는 가장 좋은 방법이라고 생각합니다. '숫자'는 숫자 키만 또는 연속적인 숫자 키만 의미 할 수 있으므로 두 가지 조건 중 하나를 확인하는 두 가지 기능이 아래에 나열되어 있습니다.
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에 하나를 추가하여 다음 키가 올바른 값인지 확인할 수 있습니다. 엄격한 비교는 키가 정수 유형인지 확인합니다. for 루프의 첫 번째 섹션에있는 $ base = (int) $ base 부분은 $ base가 생략되거나 정수로만 호출되도록 할 때 생략 할 수 있습니다. 그러나 모든 사람을 확신 할 수 없기 때문에 그대로 두었습니다. 어쨌든 명령문은 한 번만 실행됩니다. 나는 이것이 가장 효율적인 솔루션이라고 생각합니다.
- 메모리 현명 : 데이터 또는 키 범위를 복사하지 않습니다. array_values 또는 array_keys를 수행하는 것은 더 짧아 보일 수 있지만 (더 적은 코드) 해당 호출을 수행하면 백그라운드에서 진행되는 작업을 염두에 두십시오. 예 다른 솔루션보다 더 많은 (눈에 보이는) 진술이 있지만 그게 중요하지 않습니까?
- 시간 현명 : 데이터 및 / 또는 키를 복사 / 추출하는 데에도 시간이 걸린다는 사실 외에도이 솔루션은 foreach를 수행하는 것보다 효율적입니다. 다시 한번 foreach는 표기법이 더 짧기 때문에 어떤 사람들에게는 더 효율적으로 보일 수 있지만, 백그라운드에서 foreach는 reset, key를 호출하고 next to do는 루핑입니다. 그러나 또한 종료 조건을 확인하기 위해 valid를 호출하며, 정수 확인과의 조합으로 인해 여기서는 피할 수 있습니다.
배열 키는 정수 또는 문자열 만 될 수 있으며 "1"( "01"은 아님)과 같은 엄격한 숫자 문자열은 정수로 변환됩니다. 따라서 배열을 순차적으로 유지하려는 경우 정수 키를 확인하는 데 필요한 유일한 작업입니다. 당연히 is_indexed_array가 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;
}
사용하여 하나 : 나는이 인기가이 질문에 대한 접근 방법을 발견 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()
것이 훨씬 빠릅니다.
이에 접근하는 한 가지 방법 json_encode
은 올바른 JSON을 출력하기 위해 연관 배열과 인덱싱 된 배열을 구별하는 자체 내부 방법을 이미 가지고있는 을 피기 백하는 것 입니다.
인코딩 후 반환 된 첫 번째 문자가 {
(연관 배열) 또는 [
(인덱스 배열) 인지 확인하여이를 수행 할 수 있습니다 .
// Too short :)
function is_assoc($arr) {
ksort($arr);
return json_encode($arr)[0] === '{';
}
이미 많은 답변이 있지만 다음은 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
function array_is_assoc(array $a) {
$i = 0;
foreach ($a as $k => $v) {
if ($k !== $i++) {
return true;
}
}
return false;
}
빠르고 간결하며 메모리 효율적입니다. 값 비싼 비교, 함수 호출 또는 배열 복사가 없습니다.
xarray PHP 확장 을 사용하여
이 작업은 매우 빠르게 수행 할 수 있습니다 (PHP 5.6에서는 약 30 배 이상 빠름).
if (array_is_indexed($array)) { }
또는:
if (array_is_assoc($array)) { }
내 솔루션 :
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부터 다시 인덱싱됩니다.
내가 사용하는 방법은 다음과 같습니다.
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;
}
이 거대한 대기열에 대한 답변을 추가하는 것이 약간 무의미하다는 것을 알고 있지만 여기에는 값을 복제 할 필요가없는 읽기 가능한 O (n) 솔루션이 있습니다.
function isNumericArray($array) {
$count = count($array);
for ($i = 0; $i < $count; $i++) {
if (!isset($array[$i])) {
return FALSE;
}
}
return TRUE;
}
그들은 모두 숫자 경우 오히려 키를 확인 당신보다 반복 처리의 키에 걸쳐 볼 것이다 숫자 배열이있을 수 있는지가 존재합니다.
소스 에서 한 번 더 빠릅니다 . 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__)
);
}
}
이것이 해결책이 될 수 있습니까?
public static function isArrayAssociative(array $array) {
reset($array);
return !is_int(key($array));
}
주의 사항은 분명히 배열 커서가 재설정된다는 것입니다.하지만 배열이 순회되거나 사용되기 전에 함수가 사용되었다고 말하고 싶습니다.
로컬 벤치마킹, 디버깅, 컴파일러 프로빙, 프로파일 링 및 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;
}
<?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";
}
대답은 이미 주어졌지만 성능에 대한 잘못된 정보가 너무 많습니다. 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
PHP에 내장 기능이 없으면 O (n) 미만으로이를 수행 할 수 없습니다. 모든 키를 열거하고 정수 유형을 확인합니다. 실제로 구멍이 없는지 확인하고 싶으므로 알고리즘은 다음과 같을 수 있습니다.
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 :)
하지만 왜 귀찮게? 배열이 예상 한 유형이라고 가정하십시오. 그렇지 않다면 그것은 당신의 얼굴에 날려 버릴 것입니다-그것은 당신을위한 동적 프로그래밍입니다! 코드를 테스트하면 모든 것이 잘 될 것입니다 ...
배열의 키와 배열의 array_values () 결과 키의 차이를 비교합니다. 배열은 항상 정수 인덱스가있는 배열입니다. 키가 동일하면 연관 배열이 아닙니다.
function isHash($array) {
if (!is_array($array)) return false;
$diff = array_diff_assoc($array, array_values($array));
return (empty($diff)) ? false : true;
}
가장 인기있는 답변에 대한 수정.
이것은 조금 더 많은 처리가 필요하지만 더 정확합니다.
<?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,2,4,6)과 같은 연관성으로 간주되어야합니다. 이러한 종류의 배열은 이러한 방식으로 for 루프와 함께 사용할 수 없기 때문입니다.
$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;
}
참고 URL : https://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
'Program Tip' 카테고리의 다른 글
리소스가 이미있는 경우 POST에 대한 HTTP 응답 코드 (0) | 2020.09.29 |
---|---|
jQuery없이 AJAX 호출을 만드는 방법은 무엇입니까? (0) | 2020.09.29 |
POST 쿼리 매개 변수를 검색하는 방법은 무엇입니까? (0) | 2020.09.29 |
JavaScript에서 여러 값을 반환 하시겠습니까? (0) | 2020.09.29 |
Eclipse에서 줄 번호를 어떻게 표시 할 수 있습니까? (0) | 2020.09.29 |