Kiểm tra xem các phần tử của một mảng có trong một mảng khác trong PHP không


130

Tôi có hai mảng trong PHP như sau:

Mọi người:

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

Truy nã tội phạm:

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
)

Làm thế nào để kiểm tra nếu bất kỳ của dân yếu tố nằm trong các tội phạm Wanted mảng?

Trong ví dụ này, nó sẽ quay trở lại true20đang ở trong Tội phạm truy nã .

Câu trả lời:


203

Bạn có thể sử dụng array_intersect().

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

8
Không thể sử dụng khoảng trống () với bất kỳ thứ gì khác ngoài một biến.
Grantwparks

@grantwparks thì tại sao trong các tài liệu PHP về hàm này họ lại nói "Trả về FALSE nếu var tồn tại và có giá trị không rỗng, không bằng không. Nếu không thì trả về TRUE. ) "? Nguồn: php.net/manual/en/feft.empty.php
Pere

5
Từ trang bạn đã liên kết đến: "Trước PHP 5.5, blank () chỉ hỗ trợ các biến; mọi thứ khác sẽ dẫn đến lỗi phân tích cú pháp. Nói cách khác, các cách sau sẽ không hoạt động: trống (trim ($ name)). Thay vào đó, sử dụng trim ($ name) == false. "
Grantwparks

9
Như đã đề cập trong các ý kiến ​​tôi thấy rằng !empty không hoạt động như mong đợi . Thay vào đó, tôi đã sử dụng count():!count(array_intersect($people, $criminals));
Mattios550

3
Tại sao điều này được đánh dấu là câu trả lời với 65 phiếu bầu khi nó ném lỗi nghiêm trọng: Không thể sử dụng giá trị trả về của hàm trong ngữ cảnh ghi?
Dave Heq

31

Có chút sai khi sử dụng Array_intersect () và Count () (thay vì trống).

Ví dụ:

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

2
Không có gì sai với nó nhưng count()không được coi là hiệu suất (nếu bạn quan tâm đến tối ưu hóa vi mô, đó là)
Jake A. Smith

23

nếu 'trống' không phải là lựa chọn tốt nhất, thì sao đây:

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

hoặc là

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

22

Mã đó không hợp lệ vì bạn chỉ có thể chuyển các biến vào cấu trúc ngôn ngữ. empty()là một cấu trúc ngôn ngữ.

Bạn phải làm điều này trong hai dòng:

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

Vấn đề không phải là cấu trúc ngôn ngữ. Vấn đề là nó mong đợi một tài liệu tham khảo và Greg vượt qua một giá trị.
Artefacto

1
@Artefacto, từ php.net "Lưu ý: Bởi vì đây là cấu trúc ngôn ngữ và không phải là hàm, nên không thể gọi nó bằng các hàm biến." Nó chính xác như Paul đã nói.
Grantwparks

17

Kiểm tra hiệu năng cho in_array vs mảng_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;

Đây là kết quả:

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 nhanh hơn ít nhất 5 lần. Lưu ý rằng chúng tôi "phá vỡ" ngay khi kết quả được tìm thấy.


Cảm ơn cho điểm chuẩn. Vì vậy, nếu bạn biết bạn đang xử lý các mảng nhỏ, tốt hơn hết là ở lại array_intersect().
Tokeeen.com

issetthậm chí còn nhanh hơn Và bạn có thể sử dụng bool val để bật hoặc tắt. Ngoài ra các giá trị tìm kiếm là khóa đảm bảo không có trùng lặp. ´ararray_intersect avg: 0,52077736854553; in_array avg: 0,015597295761108; Ngay lập tức avg: 0,0077081203460693 Đổi
Cottage

1

Bạn cũng có thể sử dụng in_array như sau:

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

Mặc dù Array_intersect chắc chắn thuận tiện hơn khi sử dụng, nhưng hóa ra nó không thực sự vượt trội về hiệu năng. Tôi cũng đã tạo tập lệnh này:

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

Sau đó, tôi đã chạy cả hai đoạn tương ứng tại: http://3v4l.org/WGhO7/perf#tabshttp://3v4l.org/g1Hnu/perf#tabs và kiểm tra hiệu suất của từng đoạn. Điều thú vị là tổng thời gian CPU, tức là thời gian người dùng + thời gian hệ thống là như nhau đối với PHP5.6 và bộ nhớ cũng như vậy. Tổng thời gian CPU trong PHP5.4 ít hơn cho in_array so với mảng_intersect, mặc dù không đáng kể.


Kết quả là lừa dối. Chạy nó chỉ một lần là quá nhanh để đo bất kỳ sự khác biệt. Nếu bạn có hàng trăm hoặc hàng nghìn yêu cầu mỗi giây, các phân số của giây đó sẽ tăng lên nhanh chóng, vì vậy nếu bạn nghĩ rằng ứng dụng của bạn cần mở rộng quy mô, tôi sẽ kiên trì in_arraythực hiện.
Frank Forte

1

Đây là một cách tôi đang làm sau khi nghiên cứu một thời gian. Tôi muốn tạo một điểm cuối API của Laravel để kiểm tra xem một trường có "đang sử dụng" không, vì vậy thông tin quan trọng là: 1) bảng DB nào? 2) cột DB nào? và 3) có một giá trị trong cột đó phù hợp với các cụm từ tìm kiếm không?

Biết được điều này, chúng ta có thể xây dựng mảng kết hợp của mình:

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

Sau đó, chúng tôi có thể đặt các giá trị mà chúng tôi sẽ kiểm tra:

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

Sau đó, chúng ta có thể sử dụng array_key_exists()in_array()với nhau để thực hiện kết hợp một, hai bước và sau đó hành động theo truthyđiều kiện:

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

Tôi xin lỗi vì mã PHP dành riêng cho Laravel, nhưng tôi sẽ bỏ nó vì tôi nghĩ bạn có thể đọc nó dưới dạng mã giả. Phần quan trọng là hai ifcâu lệnh được thực thi đồng bộ.

array_key_exists()in_array()là các hàm PHP.

nguồn:

Những điều tốt đẹp về các thuật toán mà tôi đã giới thiệu ở trên là bạn có thể tạo ra một thiết bị đầu cuối như REST của GET /in-use/{table}/{column}/{value}(nơi table, columnvalue là các biến).

Bạn có thể có:

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

và sau đó bạn có thể thực hiện các yêu cầu GET như:

GET /in-use/accounts/account_name/Bob's Drywall (bạn có thể cần mã hóa uri phần cuối, nhưng thường thì không)

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

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

Cũng lưu ý rằng không ai có thể làm:

GET /in-use/users/password/dogmeat1337bởi vì passwordkhông được liệt kê trong danh sách các cột được phép của bạn cho user.

Chúc may mắn trên hành trình của bạn.


Tôi không biết điều này có liên quan gì đến câu hỏi nhưng tôi đã xem và: tôi thực sự hy vọng bạn KHÔNG BAO GIỜ sử dụng dữ liệu động $SEARCHABLE_TABLE_COLUMNS! Điều này hét lên cho một tiêm - không có vấn đề nếu có một "trình xây dựng truy vấn khung cực kỳ an toàn" giữa đó cố gắng che dấu và lọc bảng và chuỗi cột! Ở cuối bảng và chuỗi cột không thể được thêm thông qua giữ chỗ (báo cáo đã chuẩn bị) và phải được chèn trực tiếp như thế nào SELECT ... FROM {$table} WHERE {$column} = :placeholder ..... Ofc phụ thuộc vào bộ điều hợp (mysql, mongo, ...) NHƯNG đó không phải là đối số để lưu! Xin tĩnh hoặc không có danh sách =)
Cottageton
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.