如何检查多维数组中任意子数组的特定键是否存在特定值?

78

我需要在一个多维数组中搜索任意一个索引子数组中的特定值。

换句话说,我需要检查多维数组中的单个列是否存在某个值。 如果该值存在于多维数组中的任何位置,则返回true,否则返回false

$my_array = array(    
    0 =>  array(  
        "name"   => "john",  
        "id"    =>  4  
    ),  
    1   =>  array(  
        "name" =>  "mark",  
        "id" => 152  
    ), 
    2   =>  array(  
        "name" =>  "Eduard",  
        "id" => 152  
    )
);

我想知道检查数组$my_array是否包含键为"id"的值的最快和最有效的方法。例如,如果在多维数组中任何位置有id => 152,我希望返回true


如何获取找到的ID的关键数字。例如,如果我们搜索“id = 152”,结果将是“1”、“2”。@mickmackusa,@Rob - manas paul
嗨@mickmackusa,你能否帮我处理上述数组?另外,array_filter()foreach更快速地搜索吗?因为我需要在一个较大的数组中搜索相同的键。 - manas paul
@manas 我猜你想要这个。请删除你在页面上散布的所有其他评论。如果你想要多个值,只需不返回或中断即可。https://dev59.com/r3RA5IYBdhLWcg3wtwSe#16439674 - mickmackusa
18个回答

86

没有比简单的循环更快的方法。你可以将一些数组函数混合使用来完成它,但它们实际上也只是被实现成了循环。

function whatever($array, $key, $val) {
    foreach ($array as $item)
        if (isset($item[$key]) && $item[$key] == $val)
            return true;
    return false;
}

1
如何获取找到的ID的关键数字。例如,如果我们搜索“id = 152”,结果将是“1”、“2”。@Dan Grossman - manas paul

39

最简单的方式是这样的:

$my_array = array(    
    0 =>  array(  
        "name"   => "john",  
        "id"    =>  4  
    ),  
    1   =>  array(  
        "name" =>  "mark",  
        "id" => 152  
    ), 
    2   =>  array(  
        "name" =>  "Eduard",  
        "id" => 152  
    )
);

if (array_search(152, array_column($my_array, 'id')) !== FALSE) {
  echo 'FOUND!';
} else {
  echo 'NOT FOUND!';
}

如何获取搜索到的id值(152)的键值(1和2)? - manas paul

34

** PHP >= 5.5

你可以简单地使用这个。

$key = array_search(40489, array_column($userdb, 'uid'));

假设有这个多维数组:

$userdb=Array
(
(0) => Array
    (
        (uid) => '100',
        (name) => 'Sandra Shush',
        (url) => 'urlof100'
    ),

(1) => Array
    (
        (uid) => '5465',
        (name) => 'Stefanie Mcmohn',
        (pic_square) => 'urlof100'
    ),

(2) => Array
    (
        (uid) => '40489',
        (name) => 'Michael',
        (pic_square) => 'urlof40489'
    )
);

$key = array_search(40489, array_column($userdb, 'uid'));

5
为什么不直接使用$ids = array_column($array, 'id', 'id');,然后检查isset($ids[40489])呢? - Elias Van Ootegem
嗨,你介意更新你的答案并实现Elias的评论吗? - leymannx
4
重要的是要澄清给未来的研究人员知道 $key 可能是一个假值 0。为了确定 array_search() 是否找到符合条件的数据,你必须显式地检查 $key !== false$key === false,具体取决于你的需求。 - mickmackusa

25

以下是 Dan Grossman 回答的更新版本,适用于多维数组(我需要的内容):

function find_key_value($array, $key, $val)
{
    foreach ($array as $item)
    {
        if (is_array($item) && find_key_value($item, $key, $val)) return true;

        if (isset($item[$key]) && $item[$key] == $val) return true;
    }

    return false;
}

1
能否在不检查特定值的情况下实现这一点?如果键为空,则返回true,如果键不为空,则返回false。 - TinyTiger
如果您没有实际的$key值传递,该怎么办?我想搜索整个数组,而不管键是什么。 - Cary
听起来你只需要使用 PHP 函数 'array_search'。 - Friendly Code
由于输入数据仅限于2级深度,因此实现递归技术对于此任务来说是不必要的开销。如果这是一个递归任务(但它不是),那么array_walk_recursive()将只访问叶节点并消除is_array()检查。 - mickmackusa
我的数组的层数超过了2层。 - Friendly Code

8
如果你需要进行大量的“id”查找并且速度应该很快,你应该使用第二个数组,其中包含所有“id”作为键:
$lookup_array=array();

foreach($my_array as $arr){
    $lookup_array[$arr['id']]=1;
}

现在你可以非常快地检查是否存在特定id,例如:

echo (isset($lookup_array[152]))?'yes':'no';

6

在评论中,@Elias Van Ootegan提供了一个好的解决方案:

$ids = array_column($array, 'id', 'id');
echo isset($ids[40489])?"Exist":"Not Exist";

我尝试了一下,对我有用,谢谢伙计。 已编辑 注:它适用于 PHP 5.5+。

1
请注意,array_column 需要PHP 5.5+ - http://php.net/manual/en/function.array-column.php - Andrei Surdu

4

TMTOWTDI。以下是按复杂度排序的几种解决方案。

(关于复杂度的简短介绍):O(n)或“大 O”表示n表示数组中元素的数量的最坏情况,o(n)或“小 o”表示最好的情况。长话短说,你只需要担心最坏的情况,并确保它不是n ^ 2n!。这更多是计算时间随着n的增加而变化的度量,而不是总体计算时间。维基百科有一篇很好的关于计算机时间复杂性的文章

如果经验告诉我什么,那就是花太多时间优化程序的小 o 是一种明显浪费时间的行为,最好把时间用在做任何更好的事情上。

解决方案0:O(n) / o(1) 复杂度:

该解决方案的最佳情况是1次比较 - 1次循环迭代,但仅在匹配值位于数组的位置0时。最坏情况是它不在数组中,因此必须遍历数组的每个元素。

foreach ($my_array as $sub_array) {
    if (@$sub_array['id'] === 152) {
        return true;
    }
}
return false;

解决方案1: O(n) / o(n) 复杂度:

无论匹配值在数组中的哪个位置,此解决方案都必须循环整个数组,因此总是需要进行 n 次迭代。

return 0 < count(
    array_filter(
        $my_array,
        function ($a) {
            return array_key_exists('id', $a) && $a['id'] == 152;
        }
    )
);

解决方案2:O(n log n) / o(n log n)复杂度:

哈希插入是log n的来源;n个哈希插入= n * log n。最后有一个哈希查找,它是另一个log n,但是没有包括在内,因为这只是离散数学的工作方式。

$existence_hash = [];
foreach ($my_array as $sub_array) {
    $existence_hash[$sub_array['id']] = true;
}
return @$existence_hash['152'];

array_filter()的返回值转换为(bool)类型可以避免您必须计算结果或与0进行比较。对于任何正在寻找最有效技术的人(包括OP),使用array_filter()将继续迭代输入数组,即使找到匹配项,因此这不是最佳方法。 - mickmackusa
count() 调用是一个 O(1) 操作,因此使用强制转换没有优化。即使将其编写为短路 for 循环,最坏情况仍然是 O(n),因为 ID 可能不存在于 $my_array 中。 - amphetamachine
通过转换为(bool),就不需要在array_filter()的返回值上进行函数调用和条件比较,因此将其转换为布尔类型更直接、更简洁。DanGrossman的技巧(尽管我会对所有语言结构使用花括号)将是最佳表现者,因为它执行了一个条件早期返回/中断。我相信你已经知道这一点;我只是为研究人员陈述这个事实。请在您的答案中添加解释,以模范更好的发布行为给新用户。 - mickmackusa

2
我看到这篇文章是想做同样的事情,然后想到了自己的解决方案,我想为以后来访的用户提供我的解决方案(并查看是否采用这种方式会出现我没有预见到的问题)。
如果你想得到一个简单的“true”或“false”的输出,并且想要用一行代码而不需要函数或循环来实现,你可以对数组进行序列化,然后使用“stripos”搜索该值: stripos(serialize($my_array),$needle) 这对我来说似乎有效。

1

像你的问题一样,实际上是一个简单的二维数组,不是更好吗?看一下-

假设你的二维数组名为$my_array,要查找的值为$id。

function idExists($needle='', $haystack=array()){
    //now go through each internal array
    foreach ($haystack as $item) {
        if ($item['id']===$needle) {
            return true;
        }
    }
    return false;
}

"并调用它:"
idExists($id, $my_array);

正如您所看到的,它实际上只检查具有键名“id”的任何内部索引是否具有您的$value。如果键名“name”也具有$value,则此处的其他答案可能也会导致结果为真。

这个函数将成为页面上最佳的表现之一,因为它采用了早期返回并且在检查针之前不会创建 id 列数据的临时数组。 - mickmackusa

0

array_column 函数返回数组中单个列的值,我们可以通过 in_array 查找特定值。

if (in_array(152, array_column($my_array, 'id'))) {
    echo 'FOUND!';
} else {
    echo 'NOT FOUND!';
}

in_array() 是执行数组搜索的效率最低的方法之一。@ImranQamer的答案将会更好,因为它搜索键而不是值。这个答案缺少了教育性的解释。 - mickmackusa

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