web-dev-qa-db-fra.com

Comment vérifier si plusieurs clés de tableau existent

J'ai une variété de tableaux qui contiendront soit

story & message

ou juste 

story

Comment pourrais-je vérifier si un tableau contient à la fois une histoire et un message? array_key_exists() ne cherche que cette clé unique dans le tableau. 

Y a-t-il un moyen de faire cela?

65
Ryan

Si vous n'avez que 2 clés à vérifier (comme dans la question initiale), il est probablement assez facile d'appeler simplement array_key_exists() pour vérifier si les clés existent.

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

Cependant, cela ne va évidemment pas bien avec beaucoup de clés. Dans cette situation, une fonction personnalisée aiderait.

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

Voici une solution évolutive, même si vous souhaitez vérifier un grand nombre de clés:

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

Étonnamment, array_keys_exist n'existe pas?! En attendant, cela laisse un peu de place pour trouver une expression à une seule ligne pour cette tâche courante. Je pense à un script Shell ou à un autre petit programme.

Remarque: chacune des solutions suivantes utilise une syntaxe concise de déclaration de tableau […] disponible dans php 5.4+ 

array_diff + array_keys

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

(pointe du chapeau à Kim Stacks _)

Cette approche est la plus brève que j'ai trouvée. array_diff() renvoie un tableau d'éléments présents dans l'argument 1 pas présents dans argument2. Par conséquent, un tableau vide indique que toutes les clés ont été trouvées. En php 5.5, vous pourriez simplifier 0 === count(…) pour être simplement empty(…).

array_reduce + non défini

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
}

Plus difficile à lire, facile à changer. array_reduce() utilise un rappel pour itérer sur un tableau afin d'arriver à une valeur. En introduisant les clés, nous sommes intéressés par la valeur $initial de $in puis en supprimant les clés trouvées dans le source, nous pouvons nous attendre à 0 élément si toutes les clés sont trouvées.

La construction est facile à modifier car les clés qui nous intéressent s’adaptent parfaitement au résultat final.

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
}

Plus simple à écrire que la solution array_reduce mais légèrement plus difficile à modifier. array_filter est également un rappel itératif qui vous permet de créer un tableau filtré en renvoyant true (copier l'élément dans un nouveau tableau) ou false (ne pas copier) dans le rappel. Le gotchya est que vous devez changer 2 au nombre d'éléments que vous attendez. 

Cela peut être rendu plus durable, mais la lisibilité est ridicule:

$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
}
32
Mark Fox

Il me semble que la méthode la plus simple serait de loin celle-ci:

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

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

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

Impressions:

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

Cela permet également de vérifier quelles clés manquent exactement. Cela pourrait être utile pour la gestion des erreurs.

14
Petr Cibulka

Les solutions ci-dessus sont intelligentes, mais très lentes. Une boucle foreach simple avec isset est plus de deux fois plus rapide que la solution array_intersect_key.

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

(344ms vs 768ms pour les itérations de 1000000)

6
iautomation

Et ça: 

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

ne retourne vrai que si les deux ne sont pas nuls

si est nul, la clé n'est pas dans le tableau

3
David Dutkovsky

Si vous avez quelque chose comme ça:

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

Vous pouvez simplement count():

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

Cela ne fonctionne que si vous savez avec certitude que vous n’avez que ces clés de tableau, et rien d’autre.

L'utilisation de array_key_exists () ne prend en charge que la vérification d'une clé à la fois. Vous devez donc vérifier les deux séparément:

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() renvoie true si la clé est présente dans le tableau, mais c'est une fonction réelle et il y a beaucoup de choses à taper. La construction de langage isset() fera presque la même chose, sauf si la valeur testée est NULL:

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

En outre, isset permet de vérifier plusieurs variables à la fois:

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

Maintenant, pour optimiser le test pour les choses définies, vous feriez mieux d'utiliser ce "if":

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
  }
}
2
Sven

Une autre solution dans la collection:

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

J'espère que cela t'aides:

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

C'est la fonction que j'ai écrite pour moi-même à utiliser dans une classe.

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

Je suppose que vous devez rechercher plusieurs clés ALL EXIST dans un tableau. Si vous recherchez une correspondance d'au moins une touche, faites-le moi savoir afin que je puisse vous fournir une autre fonction.

Codepad ici http://codepad.viper-7.com/AKVPCH

1
Kim Stacks

essaye ça

$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
valmayaki

Quelque chose comme cela pourrait être utilisé

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

Notez la vérification sur 2, si les valeurs que vous souhaitez rechercher sont différentes, vous pouvez modifier.

Cette solution peut ne pas être efficace, mais ça marche!

Mises à jour

Dans une fonction fat:

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

}

Donc par exemple avec ceci:

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

J'espère que cela t'aides :)

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

C'est vieux et va probablement être enterré, mais c'est ma tentative.

J'ai eu un problème similaire à @ Ryan. Dans certains cas, je devais seulement vérifier si au moins 1 clé était dans un tableau et, dans certains cas, tout nécessaire être présent. 

J'ai donc écrit cette fonction:

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

C'était beaucoup plus facile que d'écrire plusieurs blocs || et &&.

0
Casper Wilkes

J'utilise quelque chose comme ça assez souvent

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

ou pour trouver les valeurs pour les clés recherchées

$wantedValues = array_intersect_key($source, array_fill_keys($wantedKeys, 1))
0
Steve
$myArray = array('key1' => '', 'key2' => '');
$keys = array('key1', 'key2', 'key3');
$keyExists = count(array_intersect($keys, array_keys($myArray)));

Retournera true, car il y a des clés du tableau $ keys dans $ myArray

0
Andrew Luca

Est-ce que ça ne marche pas?

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

Je ne sais pas si c'est une mauvaise idée, mais j'utilise une boucle foreach très simple pour vérifier plusieurs clés de tableau.

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

// lance la démo

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

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