한 배열의 요소가 PHP의 다른 배열에 있는지 확인


130

다음과 같이 PHP에 두 개의 배열이 있습니다.

사람들:

Array
(
    [0] => 3
    [1] => 20
)

수배범 :

Array
(
    [0] => 2
    [1] => 4
    [2] => 8
    [3] => 11
    [4] => 12
    [5] => 13
    [6] => 14
    [7] => 15
    [8] => 16
    [9] => 17
    [10] => 18
    [11] => 19
    [12] => 20
)

여부를 어떻게 확인합니까 어떤사람의 요소가에있는 구인 범죄자의 배열?

이 예에서는 반환해야 true하기 때문 20이다 구함 범죄자 .

답변:


204

사용할 수 있습니다 array_intersect().

$result = !empty(array_intersect($people, $criminals));

8
변수 이외의 다른 것과 함께 empty ()를 사용할 수 없습니다.
grantwparks

@grantwparks 그러면 PHP 문서에서이 함수에 대해 "var가 존재하고 비어 있지 않은 0이 아닌 값이 있으면 FALSE를 반환합니다. 그렇지 않으면 TRUE를 반환합니다. 다음 사항은 비어있는 것으로 간주됩니다. array () (빈 배열) ) "? 출처 : php.net/manual/en/function.empty.php
페레

5
링크 한 페이지에서 : "PHP 5.5 이전에는 empty ()는 변수 만 지원합니다. 그 외의 경우 구문 분석 오류가 발생합니다. 즉, 다음은 작동하지 않습니다. empty (trim ($ name)). 대신, trim ($ name) == false를 사용하십시오. "
grantwparks

9
코멘트에서 언급했듯이 !empty 예상대로 작동하지 않는 것으로 나타났습니다 . 대신 다음을 사용했습니다 count().!count(array_intersect($people, $criminals));
Mattios550

3
치명적 오류 : 쓰기 컨텍스트에서 함수 반환 값을 사용할 수없는 경우이 응답이 65 표로 표시되는 이유는 무엇입니까?
Dave Heq

31

array_intersect () 및 count () (비어있는 대신)를 사용하는 데 약간의 문제가 있습니다.

예를 들면 :

$bFound = (count(array_intersect($criminals, $people))) ? true : false;

2
거기에 아무것도 잘못이다하지만 count()(당신은 즉, 마이크로 최적화 걱정하는 경우) 성능이 좋은 간주되지 않습니다
제이크 A. 스미스

23

'비어 있음'이 최선의 선택이 아니라면 이건 어떨까요?

if (array_intersect($people, $criminals)) {...} //when found

또는

if (!array_intersect($people, $criminals)) {...} //when not found

22

언어 구조로만 변수를 전달할 수 있으므로 해당 코드는 유효하지 않습니다. empty()언어 구조입니다.

이 작업은 두 줄로해야합니다.

$result = array_intersect($people, $criminals);
$result = !empty($result);

문제는 그것이 언어 구조가 아니라는 것입니다. 문제는 참조를 예상하고 Greg가 값을 전달한다는 것입니다.
Artefacto

1
@Artefacto, php.net에서 "참고 : 이것은 함수가 아닌 언어 구조이기 때문에 변수 함수를 사용하여 호출 할 수 없습니다." Paul이 말한 것과 똑같습니다.
grantwparks

17

in_array 대 array_intersect 성능 테스트 :

$a1 = array(2,4,8,11,12,13,14,15,16,17,18,19,20);

$a2 = array(3,20);

$intersect_times = array();
$in_array_times = array();
for($j = 0; $j < 10; $j++)
{
    /***** TEST ONE array_intersect *******/
    $t = microtime(true);
    for($i = 0; $i < 100000; $i++)
    {
        $x = array_intersect($a1,$a2);
        $x = empty($x);
    }
    $intersect_times[] = microtime(true) - $t;


    /***** TEST TWO in_array *******/
    $t2 = microtime(true);
    for($i = 0; $i < 100000; $i++)
    {
        $x = false;
        foreach($a2 as $v){
            if(in_array($v,$a1))
            {
                $x = true;
                break;
            }
        }
    }
    $in_array_times[] = microtime(true) - $t2;
}

echo '<hr><br>'.implode('<br>',$intersect_times).'<br>array_intersect avg: '.(array_sum($intersect_times) / count($intersect_times));
echo '<hr><br>'.implode('<br>',$in_array_times).'<br>in_array avg: '.(array_sum($in_array_times) / count($in_array_times));
exit;

결과는 다음과 같습니다.

0.26520013809204
0.15600109100342
0.15599989891052
0.15599989891052
0.1560001373291
0.1560001373291
0.15599989891052
0.15599989891052
0.15599989891052
0.1560001373291
array_intersect avg: 0.16692011356354

0.015599966049194
0.031199932098389
0.031200170516968
0.031199932098389
0.031200885772705
0.031199932098389
0.031200170516968
0.031201124191284
0.031199932098389
0.031199932098389
in_array avg: 0.029640197753906

in_array는 최소 5 배 더 빠릅니다. 결과가 발견되는 즉시 "중단"됩니다.


벤치 마크 주셔서 감사합니다. 따라서 작은 배열을 처리하고 있다는 것을 알고 있다면array_intersect() .
Tokeeen.com 2017

isset더 빠릅니다. 그리고 bool val을 사용하여 활성화하거나 비활성화 할 수 있습니다. 또한 키로 검색 값이 중복되지 않도록합니다. ´array_intersect 평균 : 0.52077736854553; in_array 평균 : 0.015597295761108; isset 평균 : 0.0077081203460693´
cottton 19

1

다음과 같이 in_array를 사용할 수도 있습니다.

<?php
$found = null;
$people = array(3,20,2);
$criminals = array( 2, 4, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
foreach($people as $num) {
    if (in_array($num,$criminals)) {
        $found[$num] = true;
    } 
}
var_dump($found);
// array(2) { [20]=> bool(true)   [2]=> bool(true) }

array_intersect는 확실히 사용하기가 더 편리하지만 성능면에서 그다지 우수하지는 않습니다. 이 스크립트도 만들었습니다.

<?php
$found = null;
$people = array(3,20,2);
$criminals = array( 2, 4, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
$fastfind = array_intersect($people,$criminals);
var_dump($fastfind);
// array(2) { [1]=> int(20)   [2]=> int(2) }

그런 다음 http://3v4l.org/WGhO7/perf#tabshttp://3v4l.org/g1Hnu/perf#tabs 에서 각각 두 스 니펫을 실행하고 각각 의 성능을 확인했습니다. 흥미로운 점은 총 CPU 시간, 즉 사용자 시간 + 시스템 시간이 PHP5.6에서 동일하고 메모리도 동일하다는 것입니다. PHP5.4의 총 CPU 시간은 약간은 아니지만 in_array의 경우 array_intersect보다 적습니다.


결과는 기만적입니다. 한 번만 실행하면 차이를 측정하기에는 너무 빠릅니다. 초당 수백 또는 수천 개의 요청이있는 경우 1 초의 몇 분의 1이 빠르게 합산되므로 애플리케이션을 확장해야한다고 생각한다면 in_array구현을 고수 할 것 입니다.
Frank Forte

1

한동안 조사한 후에하는 방법입니다. 필드가 "사용 중"인지 확인하는 Laravel API 엔드 포인트를 만들고 싶었으므로 중요한 정보는 다음과 같습니다. 1) 어떤 DB 테이블입니까? 2) 어떤 DB 컬럼? 3) 해당 열에 검색어와 일치하는 값이 있습니까?

이를 알면 연관 배열을 구성 할 수 있습니다.

$SEARCHABLE_TABLE_COLUMNS = [
    'users' => [ 'email' ],
];

그런 다음 확인할 값을 설정할 수 있습니다.

$table = 'users';
$column = 'email';
$value = 'alice@bob.com';

그런 다음 array_key_exists()in_array()서로를 사용 하여 1, 2 단계 콤보를 실행하고 truthy조건에 따라 조치를 취할 수 있습니다.

// step 1: check if 'users' exists as a key in `$SEARCHABLE_TABLE_COLUMNS`
if (array_key_exists($table, $SEARCHABLE_TABLE_COLUMNS)) {

    // step 2: check if 'email' is in the array: $SEARCHABLE_TABLE_COLUMNS[$table]
    if (in_array($column, $SEARCHABLE_TABLE_COLUMNS[$table])) {

        // if table and column are allowed, return Boolean if value already exists
        // this will either return the first matching record or null
        $exists = DB::table($table)->where($column, '=', $value)->first();

        if ($exists) return response()->json([ 'in_use' => true ], 200);
        return response()->json([ 'in_use' => false ], 200);
    }

    // if $column isn't in $SEARCHABLE_TABLE_COLUMNS[$table],
    // then we need to tell the user we can't proceed with their request
    return response()->json([ 'error' => 'Illegal column name: '.$column ], 400);
}

// if $table isn't a key in $SEARCHABLE_TABLE_COLUMNS,
// then we need to tell the user we can't proceed with their request
return response()->json([ 'error' => 'Illegal table name: '.$table ], 400);

Laravel 전용 PHP 코드에 대해 사과드립니다. 의사 코드로 읽을 수 있다고 생각하므로 남겨 두겠습니다. 중요한 부분if동 기적으로 실행되는 두 개의 문입니다.

array_key_exists()그리고 in_array()PHP의 기능은 다음과 같습니다.

출처:

위에서 보여 드린 알고리즘의 좋은 점은 GET /in-use/{table}/{column}/{value}(where table,, are variables) column와 같은 REST 끝점을 만들 수 있다는 것 value입니다.

다음을 가질 수 있습니다.

$SEARCHABLE_TABLE_COLUMNS = [
    'accounts' => [ 'account_name', 'phone', 'business_email' ],
    'users' => [ 'email' ],
];

그런 다음 다음과 같은 GET 요청을 할 수 있습니다.

GET /in-use/accounts/account_name/Bob's Drywall (마지막 부분을 uri 인코딩해야 할 수도 있지만 일반적으로 그렇지 않습니다)

GET /in-use/accounts/phone/888-555-1337

GET /in-use/users/email/alice@bob.com

누구도 할 수없는 일입니다.

GET /in-use/users/password/dogmeat1337password대해 허용 된 열 목록에이 (가) 나열되지 않았기 때문 입니다 user.

당신의 여행에 행운을 빕니다.


나는 이것이 질문과 어떤 관련이 있는지 모르겠지만 살펴 보았습니다. 정말로 동적 데이터를 사용하지 않기를 바랍니다 $SEARCHABLE_TABLE_COLUMNS! 이것은 주입을위한 비명을 지른다. 테이블과 열 문자열을 마스킹하고 필터링하는 "초 보안 프레임 워크 쿼리 빌더"가 있더라도 상관 없다! 끝 테이블과 열 문자열은 자리 표시 자 (준비된 문)를 통해 추가 할 수 없으며 SELECT ... FROM {$table} WHERE {$column} = :placeholder ..... Ofc는 어댑터 (mysql, mongo, ...)에 의존하지만 저장할 인수가 아닙니다! Pls 정적 또는 목록 없음 =)
cottton 19
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.