Як перевірити, чи існує кілька ключів масиву


87

У мене є безліч масивів, які або будуть містити

story & message

або просто

story

Як перевірити, чи містить масив як історію, так і повідомлення? array_key_exists()шукає лише той єдиний ключ у масиві.

Чи є спосіб зробити це?


2
Якщо "історія" буде в обох випадках, здається, вам дійсно потрібно просто перевірити наявність "повідомлення".
Wyzard

5
Використовуючи array_intersect_key()порівняти масив ключів, який потрібно перевірити, із масивом, який ви перевіряєте. Якщо довжина результату збігається з масивом ключів для перевірки, вони всі присутні.
Michael Berkowski

Уайзард, у мене є інші масиви, які містять повідомлення, але не історію, але вони мають інші ключі, які масив із історією або історією та повідомленням міститиме лише. Дякую
Райан

Ви плутаєте тут ключі та значення? Чи відформатований масив як, ["story & message" => "value"]чи це більше схоже["story & message"]
GordonM

Відповіді:


69

Якщо у вас є лише 2 ключі для перевірки (як у вихідному питанні), можливо, досить просто дзвонити array_key_exists()двічі, щоб перевірити, чи існують ключі.

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

Однак це, очевидно, погано масштабується для багатьох клавіш. У цій ситуації корисна спеціальна функція.

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

3
Якщо люди вважають, що інші рішення краще перевірити, чи є в масиві два члени, їм не повинен подобатися чіткий читабельний код або продуктивність :)
Алекс,

Це, мабуть, найпростіше рішення, якщо потрібних клавіш порівняно мало. Якщо вони стануть нечитабельними, якщо вони щось приблизно 20 або 30.
apokryfos

1
@apokryfos Погодьтеся, але це відповідає на запитання ОП.
alex

2
@alex єдина проблема полягає в тому, що якщо $keysмістить один елемент, якого немає,$arr а інший, що знаходиться в ньому, !array_diff_keyповертається порожнім => false( приклад 3v4l ) ...
CPHPython

3
Я вважаю, що це можна зробити більш читабельним, використовуючи, !array_diff($keys, array_keys($array));оскільки когнітивне навантаження задіює трохи менше результатів array_flip.
moopet

193

Ось рішення, яке масштабоване, навіть якщо ви хочете перевірити наявність великої кількості ключів:

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

Я хотів би знати причину, чому це було проголосовано .. afaik це швидше, тому що array_intersect_key реалізовано в C, і вам не знадобиться цикл
Erfan

Насправді досить розумний, молодець - хоч і трохи важкий для читання.
Jon z

Дякую :) Це дивно, що PHP не має вбудованої функції для цього - це досить поширене явище. Існує маса класів перевірки вводу користувачами, які роблять це, але для більшості випадків використання це надмірно
Ерфан

12
Дійсно розумне рішення, але воно справді повільніше (приблизно на 50% повільніше на моєму ящику), ніж просто: `` $ ok = true; foreach ($ потрібно як $ поле) {if (! array_key_exists ($ field, $ data)) $ ok = false; }
Ож

@ Ож, крім цього array_key_exists є повільнішим, ніж
isset

34

Напрочуд array_keys_existне існує ?! Тим часом, що залишає трохи місця, щоб зрозуміти однорядковий вираз для цього загального завдання. Я думаю про сценарій оболонки або іншу невелику програму.

Примітка: кожне з наступних рішень використовує стислий […]синтаксис оголошення масиву, доступний у php 5.4+

array_diff + array_keys

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

(кінчик капелюха Кім Стек )

Цей підхід є найкоротшим, який я знайшов. array_diff()повертає масив елементів присутніх в аргумент 1 НЕ присутній в argument2. Тому порожній масив означає, що всі ключі знайдені. У php 5.5 ви можете спростити, 0 === count(…)щоб бути простим 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
}

Важче читається, легко змінюється. array_reduce()використовує зворотний виклик для ітерації масиву, щоб отримати значення. Подаючи ключі, які нас цікавлять $initialзначення, $inа потім видаляючи ключі, знайдені у джерелі, ми можемо очікувати закінчення з 0 елементами, якщо всі ключі були знайдені.

Конструкцію легко модифікувати, оскільки клавіші, які нас цікавлять, добре прилягають до нижнього рядка.

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
}

Написати простіше, ніж array_reduceрішення, але трохи хитріше редагувати. array_filterтакож є ітераційним зворотним викликом, що дозволяє створити відфільтрований масив, повернувши true (скопіювати елемент у новий масив) або false (не копіювати) у зворотному виклику. Суть полягає в тому, що ви повинні змінити 2кількість предметів, яку ви очікуєте.

Це можна зробити більш довговічним, але на межі недовірливої ​​читабельності:

$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
різниця буде незначною для невеликих наборів. якщо ви пишете бібліотеку / фреймворк, яка обробляє великі набори даних, вам, мабуть, слід перевірити ефективність кожного блоку, щоб знайти вузькі місця, а не передчасно оптимізувати.
Mark Fox

16

Мені здається, що найпростішим методом був би такий:

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

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

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

Друк:

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

Це також дозволяє перевірити, яких клавіш точно не вистачає. Це може бути корисно для обробки помилок.


Це те, заради чого я сюди прийшов!
eNeMetcH

8

Ще одне можливе рішення:

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

7

Вищевказані рішення розумні, але дуже повільні. Простий цикл foreach з isset є більш ніж удвічі швидшим за array_intersect_keyрішення.

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

(344 мс проти 768 мс за 1000000 ітерацій)


isset поверне false, якщо ['key' => null], а іноді у вас є масиви з нульовими значеннями. Ви повинні використовувати array_key_exists замість
isset

Мені довелося тут використовувати протилежне через передчасне повернення з false( у цьому випадку falseзамінює true). Отже, що підходить для моїх потреб, це foreach ($keys as $key) { if (array_key_exists($key, $array)) { return true; }} return false;мої потреби, якщо anyключ у масиві існує в іншому масиві ...
Джефф,

1
Я б не називав +/- 400 мс понад мільйон клавіш "дуже повільно", але я лише людина!
colonelclick

3

Якщо у вас є щось подібне:

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

Ви можете просто count():

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

Це працює, лише якщо ви точно знаєте, що у вас є ТІЛЬКИ ці ключі масиву, і нічого іншого.

Використання array_key_exists () підтримує перевірку лише одного ключа за раз, тому вам потрібно буде перевірити обидва окремо:

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()повертає true, якщо ключ присутній у масиві, але це реальна функція, яку потрібно багато ввести. Конструкція мови isset()буде робити майже те ж саме, за винятком випадків, якщо перевіряється значення NULL:

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

Крім того, isset дозволяє одночасно перевіряти кілька змінних:

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

Тепер, щоб оптимізувати тест для встановлених речей, краще скористайтеся цим "якщо":

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

Як що до цього:

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

повертає true, якщо обидва значення не мають значення null

якщо має значення null, ключ відсутній у масиві


1
якщо значення $arr['key1']або $arr['key2']є null, код буде, ключ все ще існує.
Xorifelse

Я написав тест, будь ласка, подивіться на нього @Xorifelse test і, будь ласка, виправте мене, якщо помиляюся. FYI: того часу я знав лише версію PHP 5.6. *, Тому робив це лише для неї.
Девід Дутковський,

Що намагається виконати цей код? Чому ви не просто використовуєте foreachцикл?
Xorifelse

Я хотів додати доказ того, що issetфункція працює, як я це мав на увазі, але тепер я усвідомлюю, що ви мали рацію, ключі все ще залишаються в масиві, і тому моя відповідь неправильна, дякую за відгук. Так, я міг би цим скористатися foreach.
Девід Дутковський

3

Я використовую щось подібне досить часто

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

або знайти значення для шуканих ключів

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

2

спробуйте це

$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

Цю функцію я написав для себе в класі.

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

Я припускаю, що вам потрібно перевірити наявність декількох ключів ВСЕ ІСНУЄТЬСЯ в масиві. Якщо ви шукаєте збіг принаймні однієї клавіші, повідомте мене, щоб я міг надати іншу функцію.

Кодпад тут http://codepad.viper-7.com/AKVPCH


1
Рішення прекрасне, але там закопаний симпатичний однолінійний самоцвіт:if (0 === count(array_diff(['key1','key2','key3'], array_keys($lookIn)))) { // all keys exist } else { // nope }
Марк Фокс,

Те, що ви пишете, є правдою. Я вважаю, що моя функція є читабельнішою, хоча і детально. Звичайно, я міг помилитися. Дякую, що прокоментували мою відповідь. Я дізнаюся щось нове.
Кім Стек

1

Сподіваюся, це допоможе:

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

1

Це старо і, можливо, його поховають, але це моя спроба.

У мене була проблема, подібна до @Ryan. У деяких випадках мені потрібно було лише перевірити, чи принаймні 1 ключ міститься в масиві, а в деяких випадках всі повинні були бути присутніми.

Тому я написав цю функцію:

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

Це було набагато простіше, ніж писати декілька ||та &&блоки.


0

Це не працює?

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

2
Константи не можуть бути масивами ... :)
Свен

Я завжди забуваю $, коли не пишу у своєму суперкоді перевірку автозаповнення IDE. =)
Ківі

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

// запустити демо

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

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

0

Я не впевнений, що це погана ідея, але я використовую дуже простий цикл foreach для перевірки декількох ключів масиву.

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

Поверне true, оскільки в $ myArray є ключі від масиву $ keys


0

Щось як це можна було б використати

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

Зверніть увагу на галочку 2, якщо значення, які потрібно шукати, відрізняються, ви можете їх змінити.

Це рішення може бути неефективним, але воно працює!

Оновлення

В одній функції жиру :

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

}

Так, наприклад, з цим:

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

Сподіваюся, це допомагає :)


0

Зазвичай я використовую функцію для перевірки мого допису, і це відповідь і на це запитання, тому дозвольте мені його опублікувати.

для виклику своєї функції я буду використовувати масив 2 таким чином

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

тоді моя функція буде виглядати так

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

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

        return $validation;
    }

це виведе це

"обов'язково": ["ім'я користувача", "пароль", "будь-яке інше поле"]

тож ця функція виконує перевірку та повернення всіх відсутніх полів запиту на повідомлення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.