Cách kiểm tra xem có nhiều khóa mảng tồn tại hay không


87

Tôi có nhiều mảng sẽ chứa

story & message

hay chỉ

story

Làm cách nào để kiểm tra xem một mảng có chứa cả câu chuyện và tin nhắn hay không? array_key_exists()chỉ tìm kiếm khóa duy nhất đó trong mảng.

Có cách nào để làm việc này không?


2
Nếu "câu chuyện" sẽ ở đó trong cả hai trường hợp, có vẻ như bạn thực sự chỉ cần kiểm tra "tin nhắn".
Wyzard

5
Sử dụng array_intersect_key()so sánh một mảng khóa bạn muốn xác minh với mảng bạn đang kiểm tra. Nếu độ dài của đầu ra giống với dãy khóa cần kiểm tra, chúng đều có mặt.
Michael Berkowski

Wyzard, tôi có các mảng khác chứa thông điệp, nhưng không phải là câu chuyện, nhưng những mảng đó có các khóa khác mà một mảng có câu chuyện hoặc câu chuyện và thông báo sẽ chỉ chứa. Cảm ơn
Ryan

Bạn có nhầm lẫn giữa các khóa và giá trị ở đây không? Mảng có được định dạng giống ["story & message" => "value"]hay giống hơn["story & message"]
GordonM

Câu trả lời:


69

Nếu bạn chỉ có 2 chìa khóa để kiểm tra (như trong câu hỏi ban đầu), có lẽ bạn chỉ cần gọi array_key_exists()hai lần để kiểm tra xem chìa khóa có tồn tại hay không.

if (array_key_exists("story", $arr) && array_key_exists("message", $arr)) {
    // Both keys exist.
}

Tuy nhiên, điều này rõ ràng không mở rộng quy mô tốt cho nhiều phím. Trong tình huống đó, một chức năng tùy chỉnh sẽ hữu ích.

function array_keys_exists(array $keys, array $arr) {
   return !array_diff_key(array_flip($keys), $arr);
}

3
Nếu mọi người nghĩ rằng các giải pháp khác tốt hơn để kiểm tra xem một mảng có hai thành viên hiện diện hay không, thì họ phải không thích mã hoặc hiệu suất rõ ràng có thể đọc được :)
alex

Đây có lẽ là giải pháp đơn giản nhất nếu số lượng khóa cần thiết của bạn tương đối ít. Nếu sẽ trở nên không thể đọc được nếu chúng giống như 20 hoặc 30.
apokryfos

1
@apokryfos Đồng ý, nhưng nó trả lời câu hỏi của OP.
alex

2
@ Alex vấn đề duy nhất là nếu $keysmột yếu tố mà không phải là ở$arr và phần còn lại là ở trong đó, !array_diff_keylợi nhuận trống => false( 3v4l dụ ) ...
CPHPython

3
Tôi nghĩ rằng điều này có thể dễ đọc hơn bằng cách sử dụng !array_diff($keys, array_keys($array));vì có ít tải trọng nhận thức hơn liên quan đến việc tìm ra những thứ array_flipđó.
moopet

193

Đây là một giải pháp có thể mở rộng, ngay cả khi bạn muốn kiểm tra một số lượng lớn khóa:

<?php

// The values in this arrays contains the names of the indexes (keys) 
// that should exist in the data array
$required = array('key1', 'key2', 'key3');

$data = array(
    'key1' => 10,
    'key2' => 20,
    'key3' => 30,
    'key4' => 40,
);

if (count(array_intersect_key(array_flip($required), $data)) === count($required)) {
    // All required keys exist!
}

Tôi muốn biết lý do tại sao điều này bị phản đối .. afaik điều này nhanh hơn vì array_intersect_key được triển khai trong C và bạn sẽ không cần vòng lặp
Erfan

Thực ra khá thông minh, được thực hiện tốt - mặc dù hơi khó đọc.
Jon z

Cảm ơn :) Thật kỳ lạ là PHP không có chức năng tích hợp để làm điều này - nó khá phổ biến. Có rất nhiều lớp xác nhận người dùng nhập vào mà làm điều này, nhưng đối với hầu hết các trường hợp sử dụng quá mức cần thiết của nó
Erfan

12
Giải pháp thông minh thực sự nhưng nó thực sự chậm hơn (chậm hơn khoảng 50% trên hộp của tôi) so với một giải pháp đơn giản: `` $ ok = true; foreach ($ bắt buộc là $ field) {if (! array_key_exists ($ field, $ data)) $ ok = false; }
Ozh

@Ozh ngoài điều đó ra array_key_exists chậm hơn
Isset

34

Đáng ngạc nhiên là array_keys_existkhông tồn tại ?! Trong thời gian tạm thời, để lại một số không gian để tìm ra một biểu thức dòng duy nhất cho nhiệm vụ chung này. Tôi đang nghĩ đến một kịch bản shell hoặc một chương trình nhỏ khác.

Lưu ý: mỗi giải pháp sau đây sử dụng […]cú pháp khai báo mảng ngắn gọn có sẵn trong php 5.4+

array_diff + array_keys

if (0 === count(array_diff(['story', 'message', '…'], array_keys($source)))) {
  // all keys found
} else {
  // not all
}

(đầu mũ cho Kim Stacks )

Cách tiếp cận này là ngắn gọn nhất mà tôi tìm thấy. array_diff()trả về một mảng các mục có trong đối số 1 không có trong đối số 2. Do đó, một mảng trống cho biết tất cả các khóa đã được tìm thấy. Trong php 5.5, bạn có thể đơn giản hóa 0 === count(…)thành đơn giản empty(…).

array_reduce + unset

if (0 === count(array_reduce(array_keys($source), 
    function($in, $key){ unset($in[array_search($key, $in)]); return $in; }, 
    ['story', 'message', '…'])))
{
  // all keys found
} else {
  // not all
}

Khó đọc hơn, dễ thay đổi. array_reduce()sử dụng một lệnh gọi lại để lặp qua một mảng để đi đến một giá trị. Bằng cách cung cấp các khóa, chúng tôi quan tâm đến $initialgiá trị của $invà sau đó xóa các khóa được tìm thấy trong nguồn, chúng tôi có thể mong đợi kết thúc bằng 0 phần tử nếu tất cả các khóa được tìm thấy.

Cấu trúc dễ dàng sửa đổi vì các phím mà chúng tôi quan tâm nằm vừa vặn ở điểm mấu chốt.

array_filter & in_array

if (2 === count(array_filter(array_keys($source), function($key) { 
        return in_array($key, ['story', 'message']); }
    )))
{
  // all keys found
} else {
  // not all
}

Viết đơn giản hơn so với array_reducegiải pháp nhưng hơi khó chỉnh sửa. array_filtercũng là một lệnh gọi lại lặp đi lặp lại cho phép bạn tạo một mảng đã lọc bằng cách trả về true (sao chép mục vào mảng mới) hoặc false (không sao chép) trong lệnh gọi lại. Điểm mấu chốt là bạn phải thay đổi 2số lượng mặt hàng mà bạn mong đợi.

Điều này có thể được làm lâu bền hơn nhưng rất nguy hiểm về khả năng đọc:

$find = ['story', 'message'];
if (count($find) === count(array_filter(array_keys($source), function($key) use ($find) { return in_array($key, $find); })))
{
  // all keys found
} else {
  // not all
}

3
sự khác biệt sẽ không đáng kể đối với các bộ nhỏ. nếu bạn đang viết một thư viện / khung công tác xử lý các bộ dữ liệu lớn, bạn có thể nên kiểm tra hiệu suất từng đơn vị để tìm các điểm nghẽn thay vì tối ưu hóa sớm.
Mark Fox

16

Đối với tôi, dường như phương pháp đơn giản nhất cho đến nay sẽ là:

$required = array('a','b','c','d');

$values = array(
    'a' => '1',
    'b' => '2'
);

$missing = array_diff_key(array_flip($required), $values);

Bản in:

Array(
    [c] => 2
    [d] => 3
)

Điều này cũng cho phép kiểm tra chính xác khóa nào bị thiếu. Điều này có thể hữu ích cho việc xử lý lỗi.


Đây là những gì tôi đến đây vì!
eNeMetcH

8

Một giải pháp khả thi hơn:

if (!array_diff(['story', 'message'], array_keys($array))) {
    // OK: all the keys are in $array
} else {
   // FAIL: some keys are not
}

7

Các giải pháp trên là khéo léo, nhưng rất chậm. Một vòng lặp foreach đơn giản với Isset nhanh hơn gấp đôi so với array_intersect_keygiải pháp.

function array_keys_exist($keys, $array){
    foreach($keys as $key){
        if(!array_key_exists($key, $array))return false;
    }
    return true;
}

(344ms so với 768ms cho 1000000 lần lặp)


Isset sẽ trả về false nếu ['key' => null] và đôi khi bạn có mảng có giá trị null. Bạn nên sử dụng array_key_exists thay isset
j4r3k

Tôi đã phải sử dụng điều ngược lại ở đây vì sự trở lại sớm với false( falseghi đè truetrong trường hợp này). Vì vậy, những gì làm việc cho nhu cầu của tôi là foreach ($keys as $key) { if (array_key_exists($key, $array)) { return true; }} return false;nhu cầu của tôi là nếu anychủ chốt trong một mảng tồn tại trong mảng khác ...
Geoff

1
Tôi sẽ không gọi +/- 400ms trên một triệu phím là "rất chậm", nhưng tôi chỉ là con người!
colonelclick vào

3

Nếu bạn có một cái gì đó như thế này:

$stuff = array();
$stuff[0] = array('story' => 'A story', 'message' => 'in a bottle');
$stuff[1] = array('story' => 'Foo');

Bạn có thể chỉ cần count():

foreach ($stuff as $value) {
  if (count($value) == 2) {
    // story and message
  } else {
    // only story
  }
}

Điều này chỉ hoạt động nếu bạn biết chắc chắn rằng bạn CHỈ có các khóa mảng này và không có gì khác.

Sử dụng array_key_exists () chỉ hỗ trợ kiểm tra một khóa tại một thời điểm, vì vậy bạn sẽ cần kiểm tra cả hai khóa riêng biệt:

foreach ($stuff as $value) {
  if (array_key_exists('story', $value) && array_key_exists('message', $value) {
    // story and message
  } else {
    // either one or both keys missing
  }
}

array_key_exists()trả về true nếu khóa có trong mảng, nhưng nó là một hàm thực và có rất nhiều thứ để nhập. Cấu trúc ngôn ngữ isset()gần như sẽ hoạt động tương tự, ngoại trừ nếu giá trị được kiểm tra là NULL:

foreach ($stuff as $value) {
  if (isset($value['story']) && isset($value['message']) {
    // story and message
  } else {
    // either one or both keys missing
  }
}

Ngoài ra, Isset cho phép kiểm tra nhiều biến cùng một lúc:

foreach ($stuff as $value) {
  if (isset($value['story'], $value['message']) {
    // story and message
  } else {
    // either one or both keys missing
  }
}

Bây giờ, để tối ưu hóa thử nghiệm cho những thứ đã được thiết lập, bạn tốt hơn nên sử dụng "nếu" này:

foreach ($stuff as $value) {
  if (isset($value['story']) {
    if (isset($value['message']) {
      // story and message
    } else {
      // only story
    }
  } else {
    // No story - but message not checked
  }
}

3

Cái này thì sao:

isset($arr['key1'], $arr['key2']) 

chỉ trả về true nếu cả hai đều không rỗng

nếu là null, khóa không có trong mảng


1
nếu giá trị của $arr['key1']hoặc $arr['key2']null, mã sẽ tồn tại, khóa vẫn tồn tại.
Xorifelse

Tôi đã viết một bài kiểm tra, vui lòng xem nó @Xorifelse test và vui lòng sửa cho tôi nếu tôi sai. FYI: thời điểm đó tôi chỉ biết phiên bản PHP 5.6. * Nên tôi chỉ làm vậy.
David Dutkovsky

Mã đó đang cố gắng hoàn thành điều gì? Tại sao bạn không chỉ sử dụng một foreachvòng lặp?
Xorifelse

Tôi muốn thêm chứng minh rằng issethàm hoạt động theo ý tôi, nhưng bây giờ tôi nhận ra rằng bạn đã đúng, các khóa vẫn còn trong một mảng và do đó câu trả lời của tôi là không đúng, cảm ơn bạn đã phản hồi. Có, tôi có thể sử dụng nó foreach.
David Dutkovsky

3

Tôi sử dụng một cái gì đó như thế này khá thường xuyên

$wantedKeys = ['story', 'message'];
$hasWantedKeys = count(array_intersect(array_keys($source), $wantedKeys)) > 0

hoặc để tìm các giá trị cho các khóa mong muốn

$wantedValues = array_intersect_key($source, array_fill_keys($wantedKeys, 1))

2

thử đi

$required=['a','b'];$data=['a'=>1,'b'=>2];
if(count(array_intersect($required,array_keys($data))>0){
    //a key or all keys in required exist in data
 }else{
    //no keys found
  }

1

Đây là hàm tôi đã viết cho chính mình để sử dụng trong một lớp.

<?php
/**
 * Check the keys of an array against a list of values. Returns true if all values in the list
 is not in the array as a key. Returns false otherwise.
 *
 * @param $array Associative array with keys and values
 * @param $mustHaveKeys Array whose values contain the keys that MUST exist in $array
 * @param &$missingKeys Array. Pass by reference. An array of the missing keys in $array as string values.
 * @return Boolean. Return true only if all the values in $mustHaveKeys appear in $array as keys.
 */
    function checkIfKeysExist($array, $mustHaveKeys, &$missingKeys = array()) {
        // extract the keys of $array as an array
        $keys = array_keys($array);
        // ensure the keys we look for are unique
        $mustHaveKeys = array_unique($mustHaveKeys);
        // $missingKeys = $mustHaveKeys - $keys
        // we expect $missingKeys to be empty if all goes well
        $missingKeys = array_diff($mustHaveKeys, $keys);
        return empty($missingKeys);
    }


$arrayHasStoryAsKey = array('story' => 'some value', 'some other key' => 'some other value');
$arrayHasMessageAsKey = array('message' => 'some value', 'some other key' => 'some other value');
$arrayHasStoryMessageAsKey = array('story' => 'some value', 'message' => 'some value','some other key' => 'some other value');
$arrayHasNone = array('xxx' => 'some value', 'some other key' => 'some other value');

$keys = array('story', 'message');
if (checkIfKeysExist($arrayHasStoryAsKey, $keys)) { // return false
    echo "arrayHasStoryAsKey has all the keys<br />";
} else {
    echo "arrayHasStoryAsKey does NOT have all the keys<br />";
}

if (checkIfKeysExist($arrayHasMessageAsKey, $keys)) { // return false
    echo "arrayHasMessageAsKey has all the keys<br />";
} else {
    echo "arrayHasMessageAsKey does NOT have all the keys<br />";
}

if (checkIfKeysExist($arrayHasStoryMessageAsKey, $keys)) { // return false
    echo "arrayHasStoryMessageAsKey has all the keys<br />";
} else {
    echo "arrayHasStoryMessageAsKey does NOT have all the keys<br />";
}

if (checkIfKeysExist($arrayHasNone, $keys)) { // return false
    echo "arrayHasNone has all the keys<br />";
} else {
    echo "arrayHasNone does NOT have all the keys<br />";
}

Tôi giả sử bạn cần kiểm tra nhiều khóa TẤT CẢ TỒN TẠI trong một mảng. Nếu bạn đang tìm kiếm sự phù hợp của ít nhất một khóa, hãy cho tôi biết để tôi có thể cung cấp một chức năng khác.

Codepad tại đây http://codepad.viper-7.com/AKVPCH


1
Giải pháp là tốt nhưng có một viên ngọc một dòng tốt đẹp bị chôn vùi:if (0 === count(array_diff(['key1','key2','key3'], array_keys($lookIn)))) { // all keys exist } else { // nope }
Mark Fox

Những gì bạn viết là sự thật. Tôi thấy chức năng của mình dễ đọc hơn mặc dù dài dòng. Tất nhiên, tôi có thể nhầm. Cảm ơn đã bình luận về câu trả lời của tôi. Tôi học một cái gì đó mới.
Kim Stacks

1

Hi vọng điêu nay co ich:

function array_keys_exist($searchForKeys = array(), $inArray = array()) {
    $inArrayKeys = array_keys($inArray);
    return count(array_intersect($searchForKeys, $inArrayKeys)) == count($searchForKeys); 
}

1

Điều này đã cũ và có thể sẽ bị chôn vùi, nhưng đây là nỗ lực của tôi.

Tôi đã gặp sự cố tương tự với @Ryan. Trong một số trường hợp, tôi chỉ cần kiểm tra xem có ít nhất 1 khóa nằm trong một mảng hay không và trong một số trường hợp, tất cả cần phải có mặt.

Vì vậy, tôi đã viết hàm này:

/**
 * A key check of an array of keys
 * @param array $keys_to_check An array of keys to check
 * @param array $array_to_check The array to check against
 * @param bool $strict Checks that all $keys_to_check are in $array_to_check | Default: false
 * @return bool
 */
function array_keys_exist(array $keys_to_check, array $array_to_check, $strict = false) {
    // Results to pass back //
    $results = false;

    // If all keys are expected //
    if ($strict) {
        // Strict check //

        // Keys to check count //
        $ktc = count($keys_to_check);
        // Array to check count //
        $atc = count(array_intersect($keys_to_check, array_keys($array_to_check)));

        // Compare all //
        if ($ktc === $atc) {
            $results = true;
        }
    } else {
        // Loose check - to see if some keys exist //

        // Loop through all keys to check //
        foreach ($keys_to_check as $ktc) {
            // Check if key exists in array to check //
            if (array_key_exists($ktc, $array_to_check)) {
                $results = true;
                // We found at least one, break loop //
                break;
            }
        }
    }

    return $results;
}

Điều này dễ dàng hơn rất nhiều so với việc phải viết nhiều ||&&khối.


0

Điều này không hoạt động?

array_key_exists('story', $myarray) && array_key_exists('message', $myarray)

2
Hằng số không thể mảng ... :)
Sven

Tôi luôn quên $ khi không viết trong IDE siêu kiểm tra mã tự động hoàn thành của mình. =)
Kiwi

0
<?php

function check_keys_exists($keys_str = "", $arr = array()){
    $return = false;
    if($keys_str != "" and !empty($arr)){
        $keys = explode(',', $keys_str);
        if(!empty($keys)){
            foreach($keys as $key){
                $return = array_key_exists($key, $arr);
                if($return == false){
                    break;
                }
            }
        }
    }
    return $return;
}

// chạy demo

$key = 'a,b,c';
$array = array('a'=>'aaaa','b'=>'ccc','c'=>'eeeee');

var_dump( check_keys_exists($key, $array));

0

Tôi không chắc, nếu đó là ý tưởng tồi nhưng tôi sử dụng vòng lặp foreach rất đơn giản để kiểm tra nhiều khóa mảng.

// get post attachment source url
$image     = wp_get_attachment_image_src(get_post_thumbnail_id($post_id), 'single-post-thumbnail');
// read exif data
$tech_info = exif_read_data($image[0]);

// set require keys
$keys = array('Make', 'Model');

// run loop to add post metas foreach key
foreach ($keys as $key => $value)
{
    if (array_key_exists($value, $tech_info))
    {
        // add/update post meta
        update_post_meta($post_id, MPC_PREFIX . $value, $tech_info[$value]);
    }
} 

0
// sample data
$requiredKeys = ['key1', 'key2', 'key3'];
$arrayToValidate = ['key1' => 1, 'key2' => 2, 'key3' => 3];

function keysExist(array $requiredKeys, array $arrayToValidate) {
    if ($requiredKeys === array_keys($arrayToValidate)) {
        return true;
    }

    return false;
}

0
$myArray = array('key1' => '', 'key2' => '');
$keys = array('key1', 'key2', 'key3');
$keyExists = count(array_intersect($keys, array_keys($myArray)));

Sẽ trả về true, vì có các khóa từ mảng $ key trong $ myArray


0

Một cái gì đó như cái này có thể được sử dụng

//Say given this array
$array_in_use2 = ['hay' => 'come', 'message' => 'no', 'story' => 'yes'];
//This gives either true or false if story and message is there
count(array_intersect(['story', 'message'], array_keys($array_in_use2))) === 2;

Lưu ý đánh dấu chọn 2, nếu các giá trị bạn muốn tìm kiếm khác nhau, bạn có thể thay đổi.

Giải pháp này có thể không hiệu quả, nhưng nó hoạt động!

Cập nhật

Trong một hàm chất béo :

 /**
 * Like php array_key_exists, this instead search if (one or more) keys exists in the array
 * @param array $needles - keys to look for in the array
 * @param array $haystack - the <b>Associative</b> array to search
 * @param bool $all - [Optional] if false then checks if some keys are found
 * @return bool true if the needles are found else false. <br>
 * Note: if hastack is multidimentional only the first layer is checked<br>,
 * the needles should <b>not be<b> an associative array else it returns false<br>
 * The array to search must be associative array too else false may be returned
 */
function array_keys_exists($needles, $haystack, $all = true)
{
    $size = count($needles);
    if($all) return count(array_intersect($needles, array_keys($haystack))) === $size;
    return !empty(array_intersect($needles, array_keys($haystack)));

}

Vì vậy, ví dụ với điều này:

$array_in_use2 = ['hay' => 'come', 'message' => 'no', 'story' => 'yes'];
//One of them exists --> true
$one_or_more_exists = array_keys_exists(['story', 'message'], $array_in_use2, false);
//all of them exists --> true
$all_exists = array_keys_exists(['story', 'message'], $array_in_use2);

Hi vọng điêu nay co ich :)


0

Tôi thường sử dụng một chức năng để xác thực bài đăng của mình và nó cũng là câu trả lời cho câu hỏi này, vì vậy hãy để tôi đăng nó.

để gọi hàm của tôi, tôi sẽ sử dụng 2 mảng như thế này

validatePost(['username', 'password', 'any other field'], $_POST))

thì chức năng của tôi sẽ như thế này

 function validatePost($requiredFields, $post)
    {
        $validation = [];

        foreach($requiredFields as $required => $key)
        {
            if(!array_key_exists($key, $post))
            {
                $validation['required'][] = $key;
            }
        }

        return $validation;
    }

cái này sẽ xuất ra cái này

"bắt buộc": ["tên người dùng", "mật khẩu", "bất kỳ trường nào khác"]

vì vậy những gì chức năng này làm là xác thực và trả về tất cả các trường bị thiếu của yêu cầu đăng.

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.