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.