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

105

我有各种不同的数组,这些数组可能会包含:

story & message
或者只是。
story

我该如何检查一个数组是否同时包含“story”和“message”?array_key_exists() 函数只能检查单个键是否存在于数组中。

有没有其他方法可以实现?


3
如果无论哪种情况下都会有“故事”,那么你似乎只需要检查“信息”即可。 - Wyzard
6
使用array_intersect_key()函数,将要验证的键名数组与待检查的数组进行比较。如果输出的长度与待检查的键名数组长度相同,则说明它们都存在。请注意保持原文意思不变,同时使翻译更加通俗易懂。 - Michael Berkowski
Wyzard,我有其他包含消息但不包含故事的数组,但这些数组具有其他键,而仅包含故事或故事和消息的数组则不具备这些键。谢谢。 - Ryan
你是否混淆了键和值?数组的格式是像 ["story & message" => "value"] 这样的吗?还是更像 ["story & message"] - GordonM
21个回答

223

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

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

16
的确是个巧妙的解决方案,但它比直接的方法要慢得多(在我的机器上大约慢50%):$ok = true; foreach( $required as $field ) { if( !array_key_exists( $field, $data ) ) $ok = false; } - Ozh
这应该可以处理数组中的重复值 return empty(array_intersect($keys, array_keys($array))); - Mei Gwilym
对于那些只想检查是否存在任何键的人,请使用> 0而不是=== count($required) - CPHPython
对于那些只想检查是否存在任何键的人,您不需要使用 > 0!empty(...) -- 只需将返回的数组作为真值/假值进行评估。 if (array_intersect_key(array_flip($required), $data)) { - mickmackusa

93
如果您只需要检查 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);
}

5
@alex,唯一的问题是如果$keys包含一个不在$arr中的元素和另一个在其中的元素,!array_diff_key将返回空值false3v4l示例)。请注意保持原文意思,同时使翻译内容通俗易懂。 - CPHPython
7
我认为可以使用!array_diff($keys, array_keys($array));让代码更易读,因为这样就不需要用到那些array_flip函数来计算差异了。 - moopet

35

令人惊讶的是,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中存在但参数2中不存在的项目的数组。因此,空数组表示找到了所有键。在php 5.5中,您可以将0 === count(…)简化为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
}

可读性较差,易于更改。 array_reduce() 使用回调函数遍历数组以得到一个值。通过将我们感兴趣的键提供给$in$initial 值,然后移除在源中找到的键,我们可以期望最终结果为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
我查了一下 https://www.php.net/manual/en/function.array-keys-exists.php,但没有找到。 - Mark Fox
我现在明白你在暗示什么了。https://www.php.net/manual/en/function.array-key-exists.php(或`key_exists()`)是提供单个键检查的全部内容。任何使用`in_array()`的方法都将是效率最低的之一。`0 === count(...)`不是必要的 - 返回的数组的真实性就足够了。 - mickmackusa

18

另外还有一个可能的解决方案:

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

15

在我看来,最简单的方法应该是这样的:

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

这还可以检查确切缺少哪些键,对于错误处理可能会很有用。


10

上述解决方案虽然巧妙,但不必要地缓慢。对于少量键的简单foreach循环速度更快。

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

我不得不使用相反的方法,因为在使用 false 进行过早返回时(在这种情况下,false 会覆盖 true),所以对于我的需求来说,以下代码是有效的:foreach ($keys as $key) { if (array_key_exists($key, $array)) { return true; }} return false; 我的需求是,如果一个数组中的 任何 键存在于另一个数组中... - Geoff

3
这个怎么样:

这是什么意思:

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

只有两者都不为空才返回true

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


1
如果$arr['key1']$arr['key2']的值为null,那么代码仍然会保留这个键。 - Xorifelse
我写了一个测试,请看一下 @Xorifelse test,如果有错误请指出。顺便提一下,那时我只知道 PHP 5.6.* 版本,所以只为它编写了代码。 - David Dutkovsky
那段代码想要实现什么?为什么不直接使用foreach循环? - Xorifelse
我想添加一个证明表明isset函数按照我的意图工作,但现在我意识到你是对的,键仍然留在数组中,因此我的答案不正确,谢谢反馈。是的,我可以使用foreach - David Dutkovsky

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

我经常使用类似这样的东西

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

或者找到所需键的值。
$wantedValues = array_intersect_key($source, array_fill_keys($wantedKeys, 1))

count(...) >0 不是必要的。(bool) array_intersect(array_keys($source), $wantedKeys) 是相同的。非空数组为真值;空数组为假值。 - mickmackusa

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
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接