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


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.