Birden çok dizi anahtarının mevcut olup olmadığı nasıl kontrol edilir


87

Aşağıdakilerden birini içerecek çeşitli dizilerim var

story & message

ya da sadece

story

Bir dizinin hem hikaye hem de mesaj içerip içermediğini nasıl kontrol ederim? array_key_exists()yalnızca dizideki tek anahtarı arar.

Bunu yapmanın bir yolu var mı?


2
Her iki durumda da "hikaye" orada olacaksa, gerçekten sadece "mesajı" kontrol etmeniz gerekiyor gibi görünüyor.
Wyzard

5
Kullanma array_intersect_key()Eğer kontrol ediyoruz dizisi ile doğrulamak istediğiniz tuşları bir dizi karşılaştırın. Çıktının uzunluğu kontrol edilecek anahtar dizisiyle aynıysa, hepsi mevcuttur.
Michael Berkowski

Wyzard, mesaj içeren, ancak hikaye içermeyen başka dizilerim var, ancak bunların yalnızca hikayesi veya hikayesi ve mesajı olan bir dizinin içereceği başka anahtarları var. Teşekkürler
Ryan

Burada anahtarları ve değerleri karıştırıyor musunuz? Dizi biçimlendirilmiş mi ["story & message" => "value"]yoksa daha mı benziyor["story & message"]
GordonM

Yanıtlar:


72

Kontrol etmeniz gereken yalnızca 2 anahtarınız varsa (asıl soruda olduğu gibi), array_key_exists()anahtarların var olup olmadığını kontrol etmek için iki kez aramak muhtemelen yeterince kolaydır .

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

Ancak bu açıkça pek çok anahtara ölçeklenmiyor. Bu durumda özel bir işlev yardımcı olacaktır.

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

3
İnsanlar bir dizinin iki üyesi olup olmadığını kontrol etmek için diğer çözümlerin daha iyi olduğunu düşünüyorlarsa, net okunabilir kodu veya performansı
alex

Gerekli anahtarlarınız nispeten azsa, bu muhtemelen en basit çözümdür. 20 veya 30 gibi bir şey olursa okunamaz hale gelirler.
apokryfos

1
@apokryfos Kabul ediyorum, ancak OP'nin sorusuna cevap veriyor.
alex

2
@alex tek sorun, içinde olmayan ve içinde olmayan bir öğe$keys içeriyorsa , boş döndürür => ( 3v4l örneği ) ...$arr!array_diff_keyfalse
CPHPython

3
Bence bu kullanımla daha okunabilir hale getirilebilir !array_diff($keys, array_keys($array));çünkü bu array_flipe- postaların çalışmasında biraz daha az bilişsel yük vardır .
moopet

194

İşte çok sayıda anahtarı kontrol etmek isteseniz bile ölçeklenebilir bir çözüm:

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

Bunun neden reddedildiğini bilmek istiyorum .. afaik bu daha hızlı çünkü array_intersect_key C de uygulandı ve bir döngüye ihtiyacınız olmayacak
Erfan

Aslında oldukça zekice, aferin - ama okumak biraz zor.
Jon z

Teşekkürler :) PHP'nin bunu yapacak yerleşik bir işlevi olmaması garip - bu oldukça yaygındır. Bunu yapan tonlarca kullanıcı girişi doğrulama sınıfı vardır, ancak çoğu kullanım durumu için aşırılık
Erfan

12
Gerçekten akıllıca bir çözüm ama gerçekten daha yavaştır (benim kutumda yaklaşık% 50 daha yavaş), basit bir çözümden daha yavaş: `` $ ok = true; foreach ($ alan olarak gerekli) {if (! array_key_exists ($ alan, $ veri)) $ ok = false; }
Ozh

@Ozh bir yana array_key_exists isset'ten daha yavaş
iautomation

34

Şaşırtıcı bir şekilde array_keys_existyok mu ?! Bu arada, bu ortak görev için tek bir satırlık ifade bulmak için biraz boşluk bırakılır. Bir kabuk komut dosyası veya başka bir küçük program düşünüyorum.

Not: Aşağıdaki çözümlerin her biri özlü kullanır […] php 5.4+ 'de bulunan dizi bildirimi sözdizimini kullanır.

array_diff + array_keys

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

( Kim Stacks'e şapka ipucu )

Bu yaklaşım, bulduğum en kısa olanı. array_diff()öğeleri bir dizi döner değişken 1 içinde mevcut olup argument2 mevcut. Bu nedenle boş bir dizi tüm anahtarların bulunduğunu gösterir. Php 5.5'te 0 === count(…)basit olmayı basitleştirebilirsiniz 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
}

Okuması daha zor, değiştirmesi kolay. array_reduce()bir değere ulaşmak için bir dizi üzerinde yinelemek için bir geri arama kullanır. Anahtarları besleyerek, $initialdeğeriyle ilgileniyoruz$in ve ardından kaynakta bulunan anahtarları kaldırarak, tüm anahtarlar bulunursa 0 öğeyle bitmeyi bekleyebiliriz.

İlgilendiğimiz anahtarlar, alt satıra hoş bir şekilde uyduğundan, yapının değiştirilmesi kolaydır.

dizi_filtresi ve dizi içi

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

Çözüme göre yazmak daha array_reducebasittir, ancak düzenlemek biraz daha zordur. array_filterayrıca geri aramada true (öğeyi yeni diziye kopyala) veya false (kopyalama) döndürerek filtrelenmiş bir dizi oluşturmanıza olanak sağlayan yinelemeli bir geri çağrıdır. Gotchya, 2beklediğiniz öğelerin sayısını değiştirmeniz gerektiğidir .

Bu daha dayanıklı hale getirilebilir ama akıl almaz okunabilirlik sınırında:

$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
küçük setler için fark önemsiz olacaktır. Büyük veri kümelerini işleyen bir kitaplık / çerçeve yazıyorsanız, zamanından önce optimize etmek yerine darboğazları bulmak için muhtemelen her birimin performansını test etmelisiniz.
Mark Fox

16

Bana öyle geliyor ki, açık ara en kolay yöntem şudur:

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

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

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

Baskılar:

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

Bu ayrıca hangi anahtarların tam olarak eksik olduğunu kontrol etmeyi sağlar. Bu, hata işleme için faydalı olabilir.


Buraya bunun için geldim!
eNeMetcH

9

Bir olası çözüm daha:

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

7

Yukarıdaki çözümler akıllıca, ancak çok yavaş. İsset ile basit bir foreach döngüsü, array_intersect_keyçözümün iki katından daha hızlıdır .

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

(1000000 yineleme için 344 ms - 768 ms)


isset, ['key' => null] ise yanlış döndürür ve bazen boş değerli dizileriniz olur.
İsset

Erken dönüş nedeniyle burada tam tersini kullanmak zorunda kaldım false( bu durumda falsegeçersiz kılmalar true). Öyleyse, ihtiyaçlarım için işe yarayan şey, foreach ($keys as $key) { if (array_key_exists($key, $array)) { return true; }} return false;ihtiyaçlarım şuydu: eğer anybir dizide anahtar başka bir dizide mevcutsa ...
Geoff

1
Bir milyondan fazla +/- 400ms tuşa "çok yavaş" demezdim, ama ben sadece insanım!
Colonelclick

3

Böyle bir şeye sahipseniz:

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

Basitçe count()şunları yapabilirsiniz :

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

Bu, yalnızca YALNIZCA bu dizi anahtarlarına sahip olduğunuzdan ve başka hiçbir şeyin olmadığından eminseniz çalışır.

Array_key_exists () kullanmak, bir seferde yalnızca bir anahtarın kontrol edilmesini destekler, bu nedenle ikisini de ayrı ayrı kontrol etmeniz gerekir:

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()Anahtar dizide mevcutsa true döndürür, ancak bu gerçek bir işlevdir ve yazılacak çok şey vardır. Dil yapısı isset(), test edilen değerin NULL olması dışında hemen hemen aynı şeyi yapacaktır:

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

Ek olarak isset, birden çok değişkeni aynı anda kontrol etmeye izin verir:

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

Şimdi, testi ayarlanan şeyler için optimize etmek için şunu kullanmanız daha iyi: "eğer":

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

Peki buna ne dersin:

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

yalnızca her ikisi de boş değilse true döndür

null ise anahtar dizide değil


1
değeri $arr['key1']veya $arr['key2']ise null, kod olacaktır, anahtar hala var olacaktır.
Xorifelse

Bir test yazdım lütfen @Xorifelse testine bakın ve yanlışsam lütfen beni düzeltin. Bilginize: o zamanlar sadece PHP 5.6. * Sürümünü biliyordum, bu yüzden sadece bunun için yaptım.
David Dutkovsky

Bu kod neyi başarmaya çalışıyor? Neden sadece foreachdöngü kullanmıyorsun ?
Xorifelse

Bu issetişlevin kastettiğim gibi çalıştığını kanıtlamak istedim , ancak şimdi anladım ki haklısınız, anahtarlar hala bir dizide kalıyor ve bu nedenle cevabım doğru değil, geri bildirim için teşekkür ederim. Evet, kullanabilirim foreach.
David Dutkovsky

3

Böyle bir şeyi oldukça sık kullanıyorum

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

veya istenen anahtarların değerlerini bulmak için

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

2

bunu dene

$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

Bir sınıf içinde kullanmak için kendim için yazdığım işlev budur.

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

Bir dizide birden çok anahtarı kontrol etmeniz gerektiğini varsayıyorum TÜM MEVCUT. En az bir tuşa sahip bir eşleşme arıyorsanız, başka bir işlev sunabilmem için bana bildirin.

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


1
Çözüm iyi ama gömülü güzel bir tek satırlık mücevher var:if (0 === count(array_diff(['key1','key2','key3'], array_keys($lookIn)))) { // all keys exist } else { // nope }
Mark Fox

Yazdıkların doğru. Ayrıntılı olsa da işlevimi daha okunaklı buluyorum. Tabii ki yanılmış olabilirim. Cevabıma yorum yaptığınız için teşekkürler. Yeni bir şey öğreniyorum.
Kim Yığınlar

1

Bu yardımcı olur umarım:

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

1

Bu eski ve muhtemelen gömülecek, ama bu benim girişimim.

@Ryan'a benzer bir sorun yaşadım. Bazı durumlarda, bir dizide en az 1 anahtarın olup olmadığını ve bazı durumlarda hepsinin gerekli olup olmadığını kontrol etmem gerekiyordu. mevcut olması .

Ben de bu işlevi yazdım:

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

Bu yazma katsayıya sahip çok daha kolay oldu ||ve &&bloklar.


0

Bu çalışmıyor mu?

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

2
Sabitler dizi olamaz ... :)
Sven

Otomatik tamamlama IDE'sini kontrol eden süper koduma yazmadığım zaman $ 'ı her zaman unutuyorum. =)
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;
}

// demoyu çalıştır

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

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

0

Kötü bir fikir mi emin değilim ama çoklu dizi anahtarını kontrol etmek için çok basit foreach döngüsü kullanıyorum.

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

Doğru döndürür, çünkü $ myArray'de $ keys dizisinden anahtarlar vardır


0

Bunun kullanılabileceği bir şey

//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'ye karşı kontrolüne dikkat edin, aramak istediğiniz değerler farklıysa değiştirebilirsiniz.

Bu çözüm verimli olmayabilir ama işe yarıyor!

Güncellemeler

Bir yağ fonksiyonunda:

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

}

Örneğin bununla:

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

Bu yardımcı olur umarım :)


0

Gönderimi doğrulamak için genellikle bir işlev kullanırım ve bu da bu soru için bir cevaptır, bu yüzden göndermeme izin verin.

işlevimi çağırmak için 2 dizisini böyle kullanacağım

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

o zaman benim fonksiyonum böyle görünecek

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

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

        return $validation;
    }

bu bunu çıkaracak

"gerekli": ["kullanıcı adı", "şifre", "başka herhangi bir alan"]

bu nedenle, bu işlevin yaptığı, gönderi isteğinin tüm eksik alanlarını doğrulamak ve döndürmektir.


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

Stackoverflow'a hoş geldiniz, biraz detaylandırıp kodu açıklayarak ve bu kodun neden bir çözüm olduğunu anlatarak cevabınızı iyileştirebilir misiniz?
Max Muster
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.