Jak sprawdzić, czy istnieje wiele kluczy tablicy


87

Mam różne tablice, które będą zawierać

story & message

Lub tylko

story

Jak mogę sprawdzić, czy tablica zawiera zarówno historię, jak i wiadomość? array_key_exists()szuka tylko tego pojedynczego klucza w tablicy.

Czy jest na to sposób?


2
Jeśli w obu przypadkach będzie tam „historia”, wygląda na to, że naprawdę wystarczy sprawdzić „wiadomość”.
Wyzard

5
Używając array_intersect_key()porównaj tablicę kluczy, które chcesz zweryfikować, z tablicą, którą sprawdzasz. Jeśli długość danych wyjściowych jest taka sama jak tablica kluczy do sprawdzenia, wszystkie są obecne.
Michael Berkowski

Wyzard, mam inne tablice, które zawierają wiadomość, ale nie historię, ale te mają inne klucze, które zawierałaby tablica z albo historią, albo tylko historią i wiadomością. Dzięki
Ryan

Czy mylisz tutaj klucze i wartości? Czy tablica jest sformatowana tak, ["story & message" => "value"]czy bardziej jak["story & message"]
GordonM,

Odpowiedzi:


72

Jeśli masz tylko 2 klucze do sprawdzenia (jak w pierwotnym pytaniu), prawdopodobnie wystarczy array_key_exists()dwukrotnie zadzwonić, aby sprawdzić, czy klucze istnieją.

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

Jednak to oczywiście nie skaluje się dobrze do wielu kluczy. W takiej sytuacji pomogłaby funkcja niestandardowa.

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

3
Jeśli ludzie uważają, że inne rozwiązania są lepsze do sprawdzania, czy tablica ma dwa elementy, nie mogą lubić przejrzystego, czytelnego kodu lub wydajności :)
alex

Jest to prawdopodobnie najprostsze rozwiązanie, jeśli wymaganych kluczy jest stosunkowo niewiele. Jeśli staną się nieczytelne, jeśli są jakieś 20 lub 30.
apokryfos

1
@apokryfos Zgadzam się, ale odpowiada na pytanie OP.
alex

2
@alex jedynym problemem jest to, że jeśli $keyszawiera jeden element, którego nie ma,$arr a inny, który się w nim znajduje, !array_diff_keyzwraca pusty => false( przykład 3v4l ) ...
CPHPython

3
Myślę, że można to uczynić bardziej czytelnymi, używając, !array_diff($keys, array_keys($array));ponieważ jest trochę mniej poznawcze obciążenie związane z opracowywaniem tych array_flips.
moopet

194

Oto rozwiązanie, które jest skalowalne, nawet jeśli chcesz sprawdzić dużą liczbę kluczy:

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

Chciałbym poznać powód, dla którego ten głos został odrzucony ... afaik, jest to szybsze, ponieważ array_intersect_key jest zaimplementowana w C i nie będziesz potrzebować pętli
Erfan

Właściwie całkiem sprytne, dobrze zrobione - choć trochę trudne do odczytania.
Jon z

Dzięki :) To dziwne, że PHP nie ma wbudowanej funkcji do tego - jest to dość powszechne. Istnieje mnóstwo klas walidacji danych wejściowych użytkownika, które to robią, ale w większości przypadków jest to przesada
Erfan

12
Rzeczywiście sprytne rozwiązanie, ale jest naprawdę wolniejsze (około 50% wolniej na moim pudełku) niż proste: `` $ ok = true; foreach ($ wymagane jako $ field) {if (! array_key_exists ($ field, $ data)) $ ok = false; }
Ozh

@Ozh poza tym array_key_exists jest wolniejsze niż isset
iautomation

34

O dziwo array_keys_existnie istnieje ?! W międzyczasie pozostawia trochę miejsca na wymyślenie pojedynczego wiersza dla tego typowego zadania. Myślę o skrypcie powłoki lub innym małym programie.

Uwaga: każde z poniższych rozwiązań używa zwięzłej […]składni deklaracji tablicy dostępnej w php 5.4+

array_diff + array_keys

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

(cynk kapelusza do Kim Stacks )

To najkrótsze podejście, jakie znalazłem. array_diff()zwraca tablicę elementów obecnych w argumencie 1, których nie ma w argumencie2. Dlatego pusta tablica wskazuje, że znaleziono wszystkie klucze. W php 5.5 możesz uprościć, 0 === count(…)aby być prostym 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
}

Trudniejsze do odczytania, łatwe do zmiany. array_reduce()używa wywołania zwrotnego do iteracji po tablicy w celu uzyskania wartości. Podając klucze, które nas interesują$initial wartości $in, a następnie usunięcie kluczy znaleźć w źródle możemy spodziewać się kończyć 0 elementów, jeśli zostały znalezione wszystkie klawisze.

Konstrukcja jest łatwa do modyfikacji, ponieważ klawisze, którymi jesteśmy zainteresowani, ładnie pasują do dolnej linii.

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
}

Prostsze pisanie niż array_reducerozwiązanie, ale nieco trudniejsze do edycji. array_filterjest również iteracyjnym wywołaniem zwrotnym, które pozwala na utworzenie przefiltrowanej tablicy przez zwrócenie wartości true (skopiuj element do nowej tablicy) lub false (nie kopiuj) w wywołaniu zwrotnym. Problem polega na tym, że musisz zmienić 2liczbę przedmiotów, których oczekujesz.

Można to uczynić trwalszym, ale na granicy niedorzecznej czytelności:

$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
różnica będzie nieistotna dla małych zestawów. Jeśli piszesz bibliotekę / framework, który obsługuje duże zestawy danych, prawdopodobnie powinieneś przetestować wydajność każdej jednostki, aby znaleźć wąskie gardła, zamiast przedwcześnie optymalizować.
Mark Fox,

16

Wydaje mi się, że zdecydowanie najłatwiejszą metodą byłoby to:

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

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

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

Wydruki:

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

Pozwala to również dokładnie sprawdzić, których kluczy brakuje. Może to być przydatne do obsługi błędów.


Po to tu przyjechałem!
eNeMetcH

9

Jeszcze jedno możliwe rozwiązanie:

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

7

Powyższe rozwiązania są sprytne, ale bardzo powolne. Prosta pętla foreach z isset jest ponad dwa razy szybsza niż array_intersect_keyrozwiązanie.

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

(344 ms vs 768 ms dla iteracji 1000000)


isset zwróci false, jeśli ['key' => null], a czasami masz tablice z wartościami null. Zamiast tego powinieneś użyć array_key_exists isset
j4r3k

Musiałem tutaj użyć odwrotności ze względu na przedwczesny powrót z false( w tym przypadku falsenadpisania true). Więc to, co działa dla moich potrzeb, to foreach ($keys as $key) { if (array_key_exists($key, $array)) { return true; }} return false;moje potrzeby, jeśli anyklucz w tablicy istnieje w innej tablicy ...
Geoff

1
Nie nazwałbym +/- 400ms powyżej miliona klawiszy „bardzo wolno”, ale jestem tylko człowiekiem!
pułkownik kliknij

3

Jeśli masz coś takiego:

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

Możesz po prostu count():

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

Działa to tylko wtedy, gdy wiesz na pewno, że masz TYLKO te klucze tablicy i nic więcej.

Używanie array_key_exists () obsługuje tylko sprawdzanie jednego klucza na raz, więc będziesz musiał sprawdzić oba osobno:

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()zwraca prawdę, jeśli klucz jest obecny w tablicy, ale jest to prawdziwa funkcja i dużo do wpisania. Konstrukcja języka isset()zrobi prawie to samo, z wyjątkiem sytuacji, gdy testowaną wartością jest NULL:

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

Dodatkowo zestaw pozwala na jednoczesne sprawdzenie wielu zmiennych:

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

Teraz, aby zoptymalizować test dla rzeczy, które są ustawione, lepiej użyj tego „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
  }
}

3

A co z tym:

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

zwraca prawdę tylko wtedy, gdy obie nie są puste

jeśli jest null, klucza nie ma w tablicy


1
jeśli wartość $arr['key1']lub $arr['key2']jest null, kod będzie, klucz nadal istnieje.
Xorifelse,

Napisałem test, spójrz na niego @ Xorifelse test i popraw mnie, jeśli się mylę. FYI: wtedy znałem tylko wersję PHP 5.6. *, Więc zrobiłem tylko dla niej.
David Dutkovsky

Co ten kod próbuje osiągnąć? Dlaczego nie używasz tylko foreachpętli?
Xorifelse

Chciałem dodać dowód, że issetfunkcja działa tak, jak chciałem, ale teraz zdaję sobie sprawę, że masz rację, klucze nadal pozostają w tablicy i dlatego moja odpowiedź jest nieprawidłowa, dziękuję za informację zwrotną. Tak, przydałbym się foreach.
David Dutkovsky

3

Często używam czegoś takiego

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

lub znaleźć wartości żądanych kluczy

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

2

Spróbuj tego

$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

To jest funkcja, którą napisałem dla siebie, aby używać jej w klasie.

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

Zakładam, że musisz sprawdzić, czy wiele kluczy WSZYSTKO ISTNIEJE w tablicy. Jeśli szukasz dopasowania co najmniej jednego klucza, daj mi znać, abym mógł zapewnić inną funkcję.

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


1
Rozwiązanie jest w porządku, ale zakopany jest ładny, jednowierszowy klejnot:if (0 === count(array_diff(['key1','key2','key3'], array_keys($lookIn)))) { // all keys exist } else { // nope }
Mark Fox

To, co piszesz, jest prawdą. Uważam, że moja funkcja jest bardziej czytelna, choć szczegółowa. Oczywiście mogłem się mylić. Dziękuję za skomentowanie mojej odpowiedzi. Dowiaduję się czegoś nowego.
Kim Stacks

1

Mam nadzieję że to pomoże:

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

1

To jest stare i prawdopodobnie zostanie zakopane, ale to moja próba.

Miałem problem podobny do @Ryan. W niektórych przypadkach potrzebowałem tylko sprawdzić, czy co najmniej 1 klucz znajduje się w tablicy, aw niektórych przypadkach wszystko było potrzebne być obecny.

Więc napisałem tę funkcję:

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

To było o wiele łatwiejsze niż pisanie wielu ||i &&bloków.


0

Czy to nie działa?

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

2
Stałe nie mogą być tablicami ... :)
Sven

Zawsze zapominam o $, gdy nie piszę w moim superkodzie sprawdzającym autouzupełnianie IDE. =)
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;
}

// uruchom demo

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

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

0

Nie jestem pewien, czy to zły pomysł, ale używam bardzo prostej pętli foreach do sprawdzania wielu kluczy tablicy.

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

Zwróci wartość true, ponieważ w $ myArray znajdują się klucze z tablicy $ keys


0

Coś takiego można by użyć

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

Zwróć uwagę na sprawdzenie z 2, jeśli wartości, które chcesz wyszukać, są inne, możesz je zmienić.

To rozwiązanie może nie być wydajne, ale działa!

Aktualizacje

W jednej funkcji tłuszczu :

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

}

Na przykład z tym:

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

Mam nadzieję że to pomoże :)


0

Zwykle używam funkcji do walidacji mojego postu i jest to również odpowiedź na to pytanie, więc pozwól mi ją opublikować.

aby wywołać moją funkcję, użyję tablicy 2 w ten sposób

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

wtedy moja funkcja będzie wyglądać tak

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

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

        return $validation;
    }

to wyświetli to

„wymagane”: [„nazwa użytkownika”, „hasło”, „dowolne inne pole”]

więc funkcja ta sprawdza poprawność i zwraca wszystkie brakujące pola żądania wiadomości.


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

Witamy w stackoverflow. Czy mógłbyś ulepszyć swoją odpowiedź, uszczegóławiając i opisując kod oraz wyjaśniając, dlaczego ten kod jest rozwiązaniem.
Max Muster
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.