So überprüfen Sie, ob mehrere Array-Schlüssel vorhanden sind

85

Ich habe eine Vielzahl von Arrays, die entweder enthalten

story & message

oder nur

story

Wie würde ich überprüfen, ob ein Array sowohl eine Story als auch eine Nachricht enthält? array_key_exists()sucht nur nach diesem einzelnen Schlüssel im Array.

Gibt es eine Möglichkeit, dies zu tun?

Ryan
quelle
2
Wenn "Geschichte" in beiden Fällen vorhanden sein wird, müssen Sie wirklich nur nach "Nachricht" suchen.
Wyzard
5
Verwenden Sie array_intersect_key()Vergleichen Sie ein Array der Schlüssel, die Sie überprüfen möchten, mit dem Array, das Sie überprüfen. Wenn die Länge der Ausgabe mit der Anzahl der zu überprüfenden Schlüssel übereinstimmt, sind alle vorhanden.
Michael Berkowski
Wyzard, ich habe andere Arrays, die Nachrichten enthalten, aber keine Story, aber diese haben andere Schlüssel, die ein Array mit Story oder Story und Nachricht nur enthalten würde. Vielen Dank
Ryan
Verwechseln Sie hier Schlüssel und Werte? Ist das Array wie formatiert ["story & message" => "value"]oder ist es eher wie["story & message"]
GordonM

Antworten:

66

Wenn Sie nur 2 Schlüssel überprüfen müssen (wie in der ursprünglichen Frage), ist es wahrscheinlich einfach genug, nur array_key_exists()zweimal anzurufen , um zu überprüfen, ob die Schlüssel vorhanden sind.

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

Dies lässt sich jedoch offensichtlich nicht gut auf viele Tasten skalieren. In dieser Situation würde eine benutzerdefinierte Funktion helfen.

function array_keys_exists(array $keys, array $arr) {
   return !array_diff_key(array_flip($keys), $arr);
}
Alex
quelle
3
Wenn die Leute denken, dass die anderen Lösungen besser sind, um zu überprüfen, ob in einem Array zwei Mitglieder vorhanden sind, dürfen sie keinen klar lesbaren Code oder keine klare Leistung mögen :)
Alex
Dies ist wahrscheinlich die einfachste Lösung, wenn nur relativ wenige Schlüssel erforderlich sind. Wenn wird unlesbar, wenn sie so etwas wie 20 oder 30 sind.
Apokryfos
1
@apokryfos stimme zu, aber es beantwortet die Frage des OP.
Alex
2
@alex das einzige Problem ist, dass, wenn ein Element$keys enthält , das nicht in$arr und ein anderes, das darin ist, !array_diff_keyleer zurückgibt => false( 3v4l Beispiel ) ...
CPHPython
3
Ich denke, dass dies durch die Verwendung besser lesbar gemacht werden kann, !array_diff($keys, array_keys($array));da die Ausarbeitung dieser array_flips etwas weniger kognitiv ist .
Moopet
193

Hier ist eine Lösung, die skalierbar ist, auch wenn Sie nach einer großen Anzahl von Schlüsseln suchen möchten:

<?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!
}
Erfan
quelle
Ich würde gerne wissen, warum dies herabgestuft wurde. Afaik das ist schneller, weil array_intersect_key in C implementiert ist und Sie keine Schleife benötigen
Erfan
Eigentlich ziemlich schlau, gut gemacht - wenn auch etwas schwer zu lesen.
Jon z
Danke :) Es ist seltsam, dass PHP keine eingebaute Funktion hat, um dies zu tun - es ist ziemlich häufig. Es gibt Unmengen von Validierungsklassen für Benutzereingaben, die dies tun, aber für die meisten Anwendungsfälle ist es übertrieben
Erfan
12
Eine clevere Lösung, aber sie ist wirklich langsamer (ungefähr 50% langsamer auf meiner Box) als eine einfache: `` `$ ok = true; foreach ($ erforderlich als $ field) {if (! array_key_exists ($ field, $ data)) $ ok = false; }
Ozh
@Ozh abgesehen davon ist array_key_exists langsamer als isset
iautomation
34

Überraschenderweise array_keys_existgibt es nicht?! In der Zwischenzeit bleibt etwas Platz, um einen einzeiligen Ausdruck für diese allgemeine Aufgabe zu finden. Ich denke an ein Shell-Skript oder ein anderes kleines Programm.

Hinweis: Jede der folgenden Lösungen verwendet eine […]präzise Array-Deklarationssyntax, die in PHP 5.4+ verfügbar ist

array_diff + array_keys

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

(Hutspitze zu Kim Stacks )

Dieser Ansatz ist der kurzeste, den ich gefunden habe. array_diff()Gibt ein Array von Elementen zurück, die in Argument 1 vorhanden sind und in Argument2 nicht vorhanden sind. Daher zeigt ein leeres Array an, dass alle Schlüssel gefunden wurden. In PHP 5.5 könnten Sie vereinfachen 0 === count(…), um einfach zu sein empty(…).

array_reduce + ungesetzt

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
}

Schwer zu lesen, leicht zu ändern. array_reduce()verwendet einen Rückruf, um über ein Array zu iterieren und einen Wert zu erhalten. Wenn wir die Schlüssel eingeben, deren $initialWert uns interessiert, $inund dann die in der Quelle gefundenen Schlüssel entfernen, können wir davon ausgehen, dass sie mit 0 Elementen enden, wenn alle Schlüssel gefunden wurden.

Die Konstruktion ist leicht zu ändern, da die Schlüssel, an denen wir interessiert sind, gut in das Endergebnis passen.

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
}

Einfacher zu schreiben als die array_reduceLösung, aber etwas schwieriger zu bearbeiten. array_filterist auch ein iterativer Rückruf, mit dem Sie ein gefiltertes Array erstellen können, indem Sie im Rückruf true (Element in neues Array kopieren) oder false (nicht kopieren) zurückgeben. Das Problem ist, dass Sie 2die Anzahl der erwarteten Elemente ändern müssen .

Dies kann haltbarer gemacht werden, steht aber kurz vor der absurden Lesbarkeit:

$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
}
Mark Fox
quelle
2
Der Unterschied ist für kleine Mengen vernachlässigbar. Wenn Sie eine Bibliothek / ein Framework schreiben, das / das große Datenmengen verarbeitet, sollten Sie wahrscheinlich jede Einheit auf Leistung testen, um Engpässe zu finden, anstatt sie vorzeitig zu optimieren.
Mark Fox
16

Es scheint mir, dass die mit Abstand einfachste Methode folgende wäre:

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

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

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

Drucke:

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

Auf diese Weise können Sie auch überprüfen, welche Schlüssel genau fehlen. Dies kann für die Fehlerbehandlung hilfreich sein.

Petr Cibulka
quelle
Dafür bin ich hergekommen!
eNeMetcH
8

Eine weitere mögliche Lösung:

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

Die oben genannten Lösungen sind clever, aber sehr langsam. Eine einfache foreach-Schleife mit isset ist mehr als doppelt so schnell wie die array_intersect_keyLösung.

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

(344 ms gegenüber 768 ms für 1000000 Iterationen)

iautomation
quelle
isset gibt false zurück, wenn ['key' => null] und manchmal Arrays mit Nullwerten vorhanden sind. Sie sollten stattdessen array_key_exists isset
j4r3k
Ich musste hier wegen der vorzeitigen Rückkehr mit das Gegenteil verwenden false( falseüberschreibt truein diesem Fall). Also, was für meine Bedürfnisse funktioniert, ist, dass foreach ($keys as $key) { if (array_key_exists($key, $array)) { return true; }} return false;meine Bedürfnisse waren, wenn der anySchlüssel in einem Array in einem anderen Array vorhanden ist ...
Geoff
Ich würde nicht +/- 400 ms über eine Million Tasten "sehr langsam" nennen, aber ich bin nur ein Mensch!
Colonelclick
3

Was ist damit:

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

Geben Sie nur true zurück, wenn beide nicht null sind

Wenn null ist, befindet sich der Schlüssel nicht im Array

David Dutkovsky
quelle
1
Wenn der Wert von $arr['key1']oder $arr['key2']ist null, der Code wird, ist der Schlüssel noch vorhanden.
Xorifelse
Ich habe einen Test geschrieben, bitte schau ihn dir an @Xorifelse Test und korrigiere mich bitte, wenn ich falsch liege . Zu Ihrer Information: Damals kannte ich nur die Version PHP 5.6. *, Also habe ich es nur dafür getan.
David Dutkovsky
Was versucht dieser Code zu erreichen? Warum benutzt du nicht nur eine foreachSchleife?
Xorifelse
Ich wollte einen Beweis hinzufügen, dass die issetFunktion so funktioniert, wie ich es gemeint habe, aber jetzt merke ich, dass Sie Recht hatten, die Schlüssel immer noch in einem Array verbleiben und meine Antwort daher nicht korrekt ist. Vielen Dank für Ihr Feedback. Ja, ich könnte es benutzen foreach.
David Dutkovsky
3

Ich benutze so etwas ziemlich oft

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

oder um die Werte für die gewünschten Schlüssel zu finden

$wantedValues = array_intersect_key($source, array_fill_keys($wantedKeys, 1))
Steve
quelle
2

Wenn Sie so etwas haben:

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

Sie könnten einfach count():

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

Dies funktioniert nur, wenn Sie sicher sind, dass Sie NUR diese Array-Schlüssel haben und sonst nichts.

Die Verwendung von array_key_exists () unterstützt jeweils nur die Überprüfung eines Schlüssels. Sie müssen daher beide separat überprüfen:

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()Gibt true zurück, wenn der Schlüssel im Array vorhanden ist, aber es ist eine echte Funktion und viel zu tippen. Das Sprachkonstrukt macht isset()fast dasselbe, außer wenn der getestete Wert NULL ist:

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

Darüber hinaus können mit isset mehrere Variablen gleichzeitig überprüft werden:

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

Um den Test für festgelegte Inhalte zu optimieren, sollten Sie dieses "Wenn" verwenden:

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

Versuche dies

$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
  }
Valmayaki
quelle
1

Dies ist die Funktion, die ich für mich selbst geschrieben habe, um sie innerhalb einer Klasse zu verwenden.

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

Ich gehe davon aus, dass Sie in einem Array nach mehreren Schlüsseln suchen müssen, die ALLE EXISTIEREN. Wenn Sie nach einer Übereinstimmung mit mindestens einem Schlüssel suchen, lassen Sie es mich wissen, damit ich eine andere Funktion bereitstellen kann.

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

Kim Stacks
quelle
1
Die Lösung ist in Ordnung, aber es gibt einen schönen einzeiligen Edelstein begraben:if (0 === count(array_diff(['key1','key2','key3'], array_keys($lookIn)))) { // all keys exist } else { // nope }
Mark Fox
Was Sie schreiben, ist wahr. Ich finde meine Funktion besser lesbar, wenn auch ausführlich. Natürlich könnte ich mich irren. Vielen Dank für den Kommentar zu meiner Antwort. Ich lerne etwas Neues.
Kim Stacks
1

Hoffe das hilft:

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

Das ist alt und wird wahrscheinlich begraben werden, aber das ist mein Versuch.

Ich hatte ein ähnliches Problem wie @Ryan. In einigen Fällen musste ich nur überprüfen, ob sich mindestens 1 Schlüssel in einem Array befand, und in einigen Fällen wurde alles benötigt anwesend sein.

Also habe ich diese Funktion geschrieben:

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

Dies war viel einfacher, als mehrere ||und &&Blöcke schreiben zu müssen .

Casper Wilkes
quelle
0

Funktioniert das nicht

array_key_exists('story', $myarray) && array_key_exists('message', $myarray)
Kiwi
quelle
2
Konstanten können keine Arrays sein ... :)
Sven
Ich vergesse immer das $, wenn ich nicht in meine Supercode-Überprüfungs-ID für die automatische Vervollständigung schreibe. =)
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;
}

// Demo ausführen

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

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

Ich bin nicht sicher, ob es eine schlechte Idee ist, aber ich benutze eine sehr einfache foreach-Schleife, um mehrere Array-Schlüssel zu überprüfen.

// 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]);
    }
} 
Codeliebhaber
quelle
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;
}
j4r3k
quelle
0
$myArray = array('key1' => '', 'key2' => '');
$keys = array('key1', 'key2', 'key3');
$keyExists = count(array_intersect($keys, array_keys($myArray)));

Gibt true zurück, da in $ myArray Schlüssel aus dem Array $ keys enthalten sind

Andrew Luca
quelle
0

So etwas könnte benutzt werden

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

Beachten Sie die Prüfung gegen 2, wenn die zu durchsuchenden Werte unterschiedlich sind, können Sie sie ändern.

Diese Lösung ist möglicherweise nicht effizient, funktioniert aber!

Aktualisierung

In einer Fettfunktion :

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

}

Also zum Beispiel damit:

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

Hoffe das hilft :)

Oluwatobi Samuel Omisakin
quelle
0

Normalerweise benutze ich eine Funktion, um meinen Beitrag zu validieren, und sie ist auch eine Antwort auf diese Frage. Lassen Sie mich sie also posten.

Um meine Funktion aufzurufen, verwende ich das 2-Array wie folgt

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

dann wird meine Funktion so aussehen

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

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

        return $validation;
    }

Dies wird dies ausgeben

"erforderlich": ["Benutzername", "Passwort", "jedes andere Feld"]

Diese Funktion überprüft also alle fehlenden Felder der Post-Anfrage und gibt sie zurück.

jerryurenaa
quelle