Come verificare se esistono più chiavi di array


87

Ho una varietà di array che conterranno

story & message

o semplicemente

story

Come posso verificare se un array contiene sia la storia che il messaggio? array_key_exists()cerca solo quella singola chiave nell'array.

C'è un modo per fare questo?


2
Se "storia" sarà presente in entrambi i casi, sembra che tu abbia davvero bisogno di controllare solo "messaggio".
Wyzard

5
Usando array_intersect_key()confronta un array delle chiavi che vuoi verificare con l'array che stai controllando. Se la lunghezza dell'output è la stessa dell'array di chiavi da controllare, sono tutte presenti.
Michael Berkowski

Wyzard, ho altri array che contengono il messaggio, ma non la storia, ma quelli hanno altre chiavi che un array con una storia o una storia e un messaggio conterrebbe solo. Grazie
Ryan

Stai confondendo chiavi e valori qui? L'array è formattato come ["story & message" => "value"]o è più simile a["story & message"]
GordonM

Risposte:


72

Se hai solo 2 chiavi da controllare (come nella domanda originale), probabilmente è abbastanza facile chiamare array_key_exists()due volte per verificare se le chiavi esistono.

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

Tuttavia, questo ovviamente non si adatta bene a molte chiavi. In quella situazione sarebbe utile una funzione personalizzata.

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

3
Se le persone pensano che le altre soluzioni siano migliori per controllare se un array ha due membri presenti, non devono apprezzare il codice o le prestazioni leggibili in modo chiaro :)
alex

Questa è probabilmente la soluzione più semplice se le chiavi richieste sono relativamente poche. If diventerà illeggibile se sono qualcosa come 20 o 30.
apokryfos

1
@apokryfos D'accordo, ma risponde alla domanda dell'OP.
alex

2
@alex l'unico problema è che se $keyscontiene un elemento che non è in$arr e un altro che è in esso, !array_diff_keyrestituisce vuoto => false( esempio 3v4l ) ...
CPHPython

3
Penso che questo possa essere reso più leggibile usando !array_diff($keys, array_keys($array));perché c'è un po 'meno carico cognitivo coinvolto nell'elaborazione di quei messaggi array_flip.
moopet

194

Ecco una soluzione scalabile, anche se desideri verificare la presenza di un numero elevato di chiavi:

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

Vorrei sapere il motivo per cui questo è stato downvoted .. afaik è più veloce perché array_intersect_key è implementato in C e non avrai bisogno di un ciclo
Erfan

Abbastanza intelligente in realtà, ben fatto, anche se un po 'difficile da leggere.
Jon z

Grazie :) È strano che PHP non abbia una funzione incorporata per farlo - è abbastanza comune. Ci sono tonnellate di classi di convalida dell'input dell'utente che lo fanno, ma per la maggior parte dei casi d'uso è eccessivo
Erfan

12
Una soluzione davvero intelligente, ma è molto più lenta (circa il 50% più lenta sulla mia scatola) di una semplice: `` $ ok = true; foreach ($ obbligatorio come $ campo) {if (! array_key_exists ($ campo, $ dati)) $ ok = false; }
Ozh

@Ozh a parte che array_key_exists è più lento di isset
iautomation

34

Sorprendentemente array_keys_existnon esiste ?! Nel frattempo che lascia un po 'di spazio per capire una singola espressione di riga per questo compito comune. Sto pensando a uno script di shell o ad un altro piccolo programma.

Nota: ciascuna delle seguenti soluzioni utilizza la […]sintassi concisa della dichiarazione di array disponibile in php 5.4+

array_diff + array_keys

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

(punta di cappello a Kim Stacks )

Questo approccio è il più breve che ho trovato. array_diff()restituisce un array di elementi presenti nell'argomento 1 non presenti nell'argomento 2. Pertanto un array vuoto indica che tutte le chiavi sono state trovate. In php 5.5 potresti semplificare 0 === count(…)per essere semplicemente 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
}

Più difficile da leggere, facile da cambiare. array_reduce()utilizza un callback per iterare su un array per arrivare a un valore. Fornendo le chiavi di cui siamo interessati al $initialvalore $ine quindi rimuovendo le chiavi trovate nel sorgente, possiamo aspettarci di finire con 0 elementi se tutte le chiavi sono state trovate.

La costruzione è facile da modificare poiché i tasti a cui siamo interessati si adattano bene alla linea di fondo.

array_filter e in_array

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

Più semplice da scrivere rispetto alla array_reducesoluzione ma leggermente più complicato da modificare.array_filterè anche un callback iterativo che consente di creare un array filtrato restituendo true (copia l'elemento in un nuovo array) o false (non copiare) nel callback. Il gotchya è che devi cambiare 2il numero di articoli che ti aspetti.

Questo può essere reso più durevole ma rasenta una leggibilità assurda:

$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
la differenza sarà trascurabile per i piccoli set. se stai scrivendo una libreria / framework che gestisce grandi set di dati, dovresti probabilmente testare le prestazioni di ciascuna unità per trovare i colli di bottiglia piuttosto che ottimizzarla prematuramente.
Mark Fox

16

Mi sembra che il metodo di gran lunga più semplice sia questo:

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

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

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

Stampe:

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

Ciò consente anche di verificare quali chiavi mancano esattamente. Questo potrebbe essere utile per la gestione degli errori.


Questo è ciò per cui sono venuto qui!
eNeMetcH

9

Un'altra possibile soluzione:

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

7

Le soluzioni di cui sopra sono intelligenti, ma molto lente. Un semplice ciclo foreach con isset è più del doppio più veloce della array_intersect_keysoluzione.

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

(344 ms contro 768 ms per 1000000 iterazioni)


isset restituirà false se ['key' => null] e talvolta si hanno array con valori null. Dovresti usare array_key_exists invece isset
j4r3k

Ho dovuto usare l'opposto qui a causa del ritorno prematuro con false( falsesostituisce truein questo caso). Quindi, ciò che funziona per le mie esigenze è che le foreach ($keys as $key) { if (array_key_exists($key, $array)) { return true; }} return false;mie esigenze erano se la anychiave in un array esiste in un altro array ...
Geoff

1
Non definirei +/- 400 ms oltre un milione di tasti "molto lenti", ma sono solo umano!
colonelclick

3

Se hai qualcosa di simile:

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

Potresti semplicemente count():

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

Funziona solo se sai per certo di avere SOLO queste chiavi array e nient'altro.

L'uso di array_key_exists () supporta solo il controllo di una chiave alla volta, quindi dovrai controllarle entrambe separatamente:

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()restituisce true se la chiave è presente nell'array, ma è una funzione reale e molto da digitare. Il costrutto del linguaggio isset()farà quasi lo stesso, tranne se il valore testato è NULL:

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

Inoltre isset consente di controllare più variabili contemporaneamente:

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

Ora, per ottimizzare il test per le cose impostate, è meglio usare questo "se":

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

Che dire di questo:

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

restituisce true solo se entrambi non sono nulli

se è null, la chiave non è nell'array


1
se il valore di $arr['key1']o $arr['key2']è null, il codice esiste, la chiave esiste ancora.
Xorifelse

Ho scritto un test per favore guardalo @Xorifelse test e per favore correggimi se sbaglio. FYI: quella volta conoscevo solo la versione PHP 5.6. * Quindi l'ho fatto solo per questo.
David Dutkovsky

Cosa sta cercando di ottenere quel codice? Perché non stai usando solo un foreachloop?
Xorifelse

Volevo aggiungere una prova che la issetfunzione funziona come intendevo, ma ora mi rendo conto che avevi ragione, i tasti rimangono ancora in un array e quindi la mia risposta non è corretta, grazie per il feedback. Sì, potrei usarlo foreach.
David Dutkovsky,

3

Uso qualcosa di simile abbastanza spesso

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

o per trovare i valori per le chiavi desiderate

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

2

prova questo

$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

Questa è la funzione che ho scritto per me stesso da utilizzare all'interno di una 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 />";
}

Presumo che sia necessario verificare la presenza di più chiavi TUTTE ESISTONO in un array. Se stai cercando una corrispondenza di almeno una chiave, fammelo sapere in modo che possa fornire un'altra funzione.

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


1
La soluzione va bene ma c'è una bella gemma di una riga sepolta:if (0 === count(array_diff(['key1','key2','key3'], array_keys($lookIn)))) { // all keys exist } else { // nope }
Mark Fox

Quello che scrivi è vero. Trovo la mia funzione più leggibile anche se prolissa. Ovviamente potrei sbagliarmi. Grazie per aver commentato la mia risposta. Imparo qualcosa di nuovo.
Kim Stacks

1

Spero che sia di aiuto:

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

1

Questo è vecchio e probabilmente verrà sepolto, ma questo è il mio tentativo.

Ho avuto un problema simile a @Ryan. In alcuni casi, dovevo controllare solo se almeno 1 chiave era in un array e, in alcuni casi, dovevano essere tutte presenti.

Quindi ho scritto questa funzione:

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

Questo è stato molto più semplice che dover scrivere più ||e &&blocchi.


0

Non funziona?

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

2
Le costanti non possono essere array ... :)
Sven

Dimentico sempre $ quando non scrivo nel mio super codice che controlla l'IDE di completamento automatico. =)
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;
}

// esegui la demo

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

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

0

Non sono sicuro, se è una cattiva idea, ma uso un ciclo foreach molto semplice per controllare più chiavi di array.

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

Restituirà true, perché ci sono chiavi dall'array $ keys in $ myArray


0

Qualcosa come questo potrebbe essere usato

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

Nota il controllo contro 2, se i valori che vuoi cercare sono diversi puoi cambiarli.

Questa soluzione potrebbe non essere efficiente, ma funziona!

Aggiornamenti

In una funzione grassa :

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

}

Quindi ad esempio con questo:

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

Spero che sia di aiuto :)


0

Di solito uso una funzione per convalidare il mio post ed è anche una risposta a questa domanda, quindi lasciatemi pubblicare.

per chiamare la mia funzione userò l'array 2 in questo modo

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

allora la mia funzione sarà simile a questa

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

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

        return $validation;
    }

questo produrrà questo

"richiesto": ["nome utente", "password", "qualsiasi altro campo"]

quindi ciò che questa funzione fa è convalidare e restituire tutti i campi mancanti della richiesta di post.


0
    $colsRequired   = ["apple", "orange", "banana", "grapes"];
    $data           = ["apple"=>"some text", "orange"=>"some text"];
    $presentInBoth  = array_intersect($colsRequired,array_keys($data));

    if( count($presentInBoth) != count($colsRequired))
        echo "Missing keys  :" . join(",",array_diff($colsRequired,$presentInBoth));
    else
        echo "All Required cols are present";

Benvenuto in stackoverflow, potresti migliorare la tua risposta elaborando un po 'e descrivendo il codice e spiegando perché questo codice è una soluzione.
Max Muster
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.