如何检查是否存在多个数组键


87

我有各种各样的数组,要么包含

story & message

要不就

story

如何检查数组是否同时包含故事和消息? array_key_exists()只在数组中查找该键。

有没有办法做到这一点?


2
如果在任何情况下都存在“故事”,听起来您真的只需要检查“消息”即可。
Wyzard

5
使用array_intersect_key()比较要验证的键的数组与要检查的数组。如果输出的长度与要检查的键数组相同,则全部存在。
Michael Berkowski 2012年

Wyzard,我还有其他包含消息但不包含故事的数组,但是这些数组具有包含故事或​​故事和消息的数组仅包含的其他键。谢谢
瑞安

您在这里混淆键和值吗?数组的格式是类似["story & message" => "value"]还是更像["story & message"]
GordonM

Answers:


69

如果您只需要检查2个键(就像在原始问题中一样),只需调用array_key_exists()两次以检查键是否存在就足够了。

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

但是,这显然不能很好地扩展到许多键。在这种情况下,自定义功能会有所帮助。

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

3
如果人们认为其他解决方案更适合检查数组是否存在两个成员,那么他们一定不喜欢清晰可读的代码或性能:)
Alex

如果您所需的密钥相对较少,这可能是最简单的解决方案。如果它们变成20或30
左右,

1
@apokryfos同意,但确实回答了OP的问题。
亚历克斯

2
@alex的唯一问题是,如果$keys包含一个不在其中的元素,而在$arr其中又包含另一个元素,则!array_diff_key返回空=> false3v4l示例)...
CPHPython

3
我认为可以通过使用使其更具可读性,!array_diff($keys, array_keys($array));因为计算这些array_flips所涉及的认知负荷要少一些。
moopet '19

193

这是一个可扩展的解决方案,即使您要检查大量的密钥,也可以:

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

我想知道为什么投票失败的原因.. afaik这是更快的,因为array_intersect_key是在C中实现的,并且您不需要循环
Erfan

实际上非常聪明,做得很好-尽管有点难以阅读。
Jon z

谢谢:)奇怪的是,PHP没有内置函数来执行此操作-这很常见。有大量的用户输入验证类可以执行此操作,但是对于大多数用例来说,它是过大的了
Erfan

12
确实有一个聪明的解决方案,但是比简单的解决方案要慢得多(在我的机器上慢了约50%):```$ ok = true; foreach($ required as $ field){if(!array_key_exists($ field,$ data))$ ok = false; }
Ozh

@Ozh除了array_key_exists慢于isset
iautomation

34

出奇 array_keys_exist是不存在?!在此期间,留出一些空间来为该常见任务找出单行表达式。我正在考虑一个shell脚本或另一个小程序。

注意:以下每个解决方案都使用[…]php 5.4+中可用的简洁数组声明语法

array_diff + array_keys

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

(给Kim Stacks的小费)

这种方法是我发现的最简单的方法。array_diff()返回参数1中存在的项目数组。因此,空数组表示找到了所有键。在PHP 5.5中,您可以简化0 === count(…)empty(…)

array_reduce +未设置

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
}

难以阅读,易于更改。array_reduce()使用回调来遍历数组以获得值。通过输入密钥,我们对...的$initial价值感兴趣$in然后删除在源代码中找到的键,如果找到了所有键,我们可以期望以0元素结尾。

结构很容易修改,因为我们感兴趣的键非常适合底线。

array_filterin_array

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

array_reduce解决方案相比,编写起来更简单,但编辑起来却有些复杂。array_filter也是一个迭代回调,它允许您通过在回调中返回true(将项目复制到新数组)或false(不复制)来创建过滤后的数组。不可思议的是,您必须更改2期望的项目数。

可以使它更耐用,但在荒谬的可读性上接近:

$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
小套的差异可以忽略不计。如果您正在编写处理大量数据的库/框架,则可能应该对每个单元进行性能测试以发现瓶颈,而不是过早地进行优化。
Mark Fox

16

在我看来,到目前为止,最简单的方法是:

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

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

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

印刷品:

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

这也允许检查哪些键正好丢失。这对于错误处理可能很有用。


这就是我来这里的目的!
eNeMetcH

8

另一种可能的解决方案:

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

7

上面的解决方案很聪明,但是很慢。具有isset的简单foreach循环的速度是array_intersect_key解决方案的两倍以上。

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

(344毫秒与768毫秒的1000000次迭代)


如果['key'=> null],则isset将返回false,并且有时您具有带有null值的数组。您应该使用array_key_exists代替isset
j4r3k

我不得不在这里使用相反的内容,因为带有false(的情况下,falseoverride true)的过早返回。所以,最适合我的需要是,foreach ($keys as $key) { if (array_key_exists($key, $array)) { return true; }} return false;我的需要是如果any一个数组中的键存在于另一个数组中……
Geoff

1
我不会将一百万个按键的+/- 400ms称为“非常慢”,但我只是人类!
Colonelclick

3

如果您有这样的事情:

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

您可以简单地count()

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

仅当您确定仅拥有这些阵列键,而没有别的时,这才起作用。

使用array_key_exists()仅支持一次检查一个密钥,因此您将需要分别检查两个密钥:

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()如果键存在于数组中,则返回true,但这是一个实函数且要键入的内容很多。语言构造isset()几乎会执行相同的操作,除非测试值是NULL:

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

另外,isset允许一次检查多个变量:

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

现在,要针对已设置的内容优化测试,最好使用以下“ 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

那这个呢:

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

仅在两者都不为null时返回true

如果为null,则键不在数组中


1
如果$arr['key1']或的值$arr['key2']null,则代码将保留键。
Xorifelse '16

我写了一个测试,请查看@Xorifelse测试,如果我错了,请更正我。仅供参考:那时我只知道PHP 5.6。*版本,所以我只这么做。
David Dutkovsky

该代码试图完成什么?为什么不仅仅使用foreach循环?
Xorifelse

我想添加一个证明isset函数可以按照我的意思工作的证明,但是现在我意识到你是对的,键仍然保留在数组中,因此我的答案不正确,感谢反馈。是的,我可以使用它foreach
David Dutkovsky

3

我经常这样使用

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

或查找所需键的值

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

2

试试这个

$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

这是我为自己编写的在类中使用的功能。

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

我假设您需要检查数组中所有存在的多个键。如果您正在寻找至少一个键的匹配项,请告诉我,以便我提供其他功能。

此处的键盘是http://codepad.viper-7.com/AKVPCH


1
该解决方案很好,但其中埋藏着一个漂亮的单行宝石:if (0 === count(array_diff(['key1','key2','key3'], array_keys($lookIn)))) { // all keys exist } else { // nope }
Mark Fox

你写的是真的。我确实发现我的函数虽然冗长但更具可读性。当然,我可能会误会。感谢您对我的回答发表评论。我学到新东西。
Kim Stacks 2014年

1

希望这可以帮助:

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

1

这是旧的,可​​能会被掩埋,但这是我的尝试。

我有一个类似于@Ryan的问题。在某些情况下,我只需要检查数组中是否至少有一个键,在某些情况下,就需要全部显示。

所以我写了这个函数:

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

这比必须编写多个||&&块要容易得多。


0

这行不通吗?

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

2
常量不能为数组... :)
Sven 2012年

当我不写超级代码检查自动完成IDE时,我总是会忘记$。=)
猕猴桃

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

//运行演示

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

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

0

我不确定这是否是个坏主意,但我使用非常简单的foreach循环来检查多个数组键。

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

将返回true,因为$ myArray中有$ keys数组中的键


0

可以使用的东西

//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的勾选,如果要搜索的值不同,则可以更改。

该解决方案可能不是有效的,但是可以起作用!

更新

一种脂肪功能:

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

}

因此,例如:

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

希望这可以帮助 :)


0

我通常使用一个函数来验证我的帖子,这也是该问题的答案,所以让我发布。

调用我的函数,我将像这样使用2数组

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

然后我的功能看起来像这样

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

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

        return $validation;
    }

这将输出

“必填”:[“用户名”,“密码”,“任何其他字段”]

因此,此功能的作用是验证并返回发布请求的所有缺失字段。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.