在 PHP 中如何通过 key = > value 在多维数组中进行搜索

有没有什么快速的方法可以得到在多维数组中找到键值对的所有子数组?我不知道阵列会有多深。

简单的例子数组:

$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1")
);

当我搜索 key = name 和 value = “ cat 1”时,函数应该返回:

array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>3,name=>"cat 1")
);

我想函数必须是递归的才能达到最深的层次。

358054 次浏览

密码:

function search($array, $key, $value)
{
$results = array();


if (is_array($array)) {
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}


foreach ($array as $subarray) {
$results = array_merge($results, search($subarray, $key, $value));
}
}


return $results;
}


$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1"));


print_r(search($arr, 'name', 'cat 1'));

产出:

Array
(
[0] => Array
(
[id] => 1
[name] => cat 1
)


[1] => Array
(
[id] => 3
[name] => cat 1
)


)

如果效率很重要,你可以这样写,所有的递归调用都将结果存储在同一个临时 $results数组中,而不是将数组合并在一起,如下所示:

function search($array, $key, $value)
{
$results = array();
search_r($array, $key, $value, $results);
return $results;
}


function search_r($array, $key, $value, &$results)
{
if (!is_array($array)) {
return;
}


if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}


foreach ($array as $subarray) {
search_r($subarray, $key, $value, $results);
}
}

这里的关键是 search_r通过引用而不是通过值获取它的第四个参数; 与号 &是至关重要的。

供参考: 如果您有一个旧版本的 PHP,那么您必须在 打电话search_r中指定引用传递部分,而不是在其声明中。也就是说,最后一行变成了 search_r($subarray, $key, $value, &$results)

SPL版本怎么样? 它可以帮你节省一些输入:

// I changed your input example to make it harder and
// to show it works at lower depths:


$arr = array(0 => array('id'=>1,'name'=>"cat 1"),
1 => array(array('id'=>3,'name'=>"cat 1")),
2 => array('id'=>2,'name'=>"cat 2")
);


//here's the code:


$arrIt = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));


foreach ($arrIt as $sub) {
$subArray = $arrIt->getSubIterator();
if ($subArray['name'] === 'cat 1') {
$outputArray[] = iterator_to_array($subArray);
}
}

最棒的是,通过使用 RecursiveDirectoryIterator 而不是 RecursiveArrayIterator,基本上相同的代码将遍历目录。SPL 是 Roxor。

SPL 唯一令人失望的地方就是它在网上的文档很糟糕。但是一些 PHP 书籍介绍了一些有用的细节,特别是 Pro PHP; 你也可以谷歌一下获得更多的信息。

我需要类似的东西,但搜索多维数组的价值... 我采取约翰的例子,并写

function _search_array_by_value($array, $value) {
$results = array();
if (is_array($array)) {
$found = array_search($value,$array);
if ($found) {
$results[] = $found;
}
foreach ($array as $subarray)
$results = array_merge($results, $this->_search_array_by_value($subarray, $value));
}
return $results;
}

我希望这对某些人有所帮助:)

if (isset($array[$key]) && $array[$key] == $value)

对快速版本的一个小改进。

Http://snipplr.com/view/51108/nested-array-search-by-value-or-key/

<?php


//PHP 5.3


function searchNestedArray(array $array, $search, $mode = 'value') {


foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key => $value) {
if ($search === ${${"mode"}})
return true;
}
return false;
}


$data = array(
array('abc', 'ddd'),
'ccc',
'bbb',
array('aaa', array('yyy', 'mp' => 555))
);


var_dump(searchNestedArray($data, 555));
function in_multi_array($needle, $key, $haystack)
{
$in_multi_array = false;
if (in_array($needle, $haystack))
{
$in_multi_array = true;
}else
{
foreach( $haystack as $key1 => $val )
{
if(is_array($val))
{
if($this->in_multi_array($needle, $key, $val))
{
$in_multi_array = true;
break;
}
}
}
}


return $in_multi_array;
}

回来张贴这个更新的任何人需要一个优化技巧对这些答案,特别是约翰库格曼的伟大的答案上面。

他发布的函数工作得很好,但是我必须优化这个场景来处理12000行的结果集。这个函数需要8秒钟来查看所有的记录,时间太长了。

我只需要这个函数来停止搜索,并在找到匹配时返回。也就是说,如果搜索 customer _ id,我们知道结果集中只有一个 customer _ id,一旦在 多维数组,我们要返回。

下面是这个函数的速度优化版本(简化了很多) ,适用于任何需要的人。与其他版本不同,它只能处理一个数组深度,不会递归,而且不需要合并多个结果。

// search array for specific key = value
public function searchSubArray(Array $array, $key, $value) {
foreach ($array as $subarray){
if (isset($subarray[$key]) && $subarray[$key] == $value)
return $subarray;
}
}

这使得匹配12000条记录的任务降低到了1.5秒。但更合理。

另一个版本从找到值的数组元素返回键值(没有递归,为了速度而优化) :

// if the array is
$arr['apples'] = array('id' => 1);
$arr['oranges'] = array('id' => 2);


//then
print_r(search_array($arr, 'id', 2);
// returns Array ( [oranges] => Array ( [id] => 2 ) )
// instead of Array ( [0] => Array ( [id] => 2 ) )


// search array for specific key = value
function search_array($array, $key, $value) {
$return = array();
foreach ($array as $k=>$subarray){
if (isset($subarray[$key]) && $subarray[$key] == $value) {
$return[$k] = $subarray;
return $return;
}
}
}

感谢所有在这里发帖的人。

$result = array_filter($arr, function ($var) {
$found = false;
array_walk_recursive($var, function ($item, $key) use (&$found) {
$found = $found || $key == "name" && $item == "cat 1";
});
return $found;
});

这是一个修订的函数,从一个约翰 K 张贴... 我只需要获取数组中的具体关键字,上面没有什么。

function search_array ( $array, $key, $value )
{
$results = array();


if ( is_array($array) )
{
if ( $array[$key] == $value )
{
$results[] = $array;
} else {
foreach ($array as $subarray)
$results = array_merge( $results, $this->search_array($subarray, $key, $value) );
}
}


return $results;
}


$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1"));


print_r(search_array($arr, 'name', 'cat 1'));

在多维数组中要小心线性搜索算法(上面是线性的) ,因为它们具有复合的复杂性,因为它的深度增加了遍历整个数组所需的迭代次数。例如:

array(
[0] => array ([0] => something, [1] => something_else))
...
[100] => array ([0] => something100, [1] => something_else100))
)

将采取最多200次迭代来找到您正在寻找的内容(如果指针在[100][1]) ,并使用适当的算法。

在这种情况下,线性算法在 O (n)(整个数组中元素的顺序总数)下执行,这很糟糕,一百万个条目(例如1000x100x10数组)平均需要500,000次迭代才能找到指针。另外,如果您决定更改多维数组的结构,会发生什么情况?如果深度超过100,PHP 会启动一个递归算法。计算机科学可以做得更好:

在可能的情况下,总是使用对象而不是多维数组:

ArrayObject(
MyObject(something, something_else))
...
MyObject(something100, something_else100))
)

并应用自定义的比较器接口和函数对它们进行排序和查找:

interface Comparable {
public function compareTo(Comparable $o);
}


class MyObject implements Comparable {
public function compareTo(Comparable $o){
...
}
}


function myComp(Comparable $a, Comparable $b){
return $a->compareTo($b);
}

你可以使用 uasort()来利用一个定制的比较器,如果你感到冒险,你应该实现自己的集合为你的对象,可以排序和管理它们(我总是扩展 ArrayObject,以包括一个搜索功能,至少)。

$arrayObj->uasort("myComp");

一旦它们被排序(uasort 是 O (n log n) ,这是最好的,因为它得到了任意数据) ,二进制搜索可以在 O (log n)时间内完成操作,即一百万个条目只需要约20次迭代搜索。据我所知,自定义比较器二进制搜索并没有在 PHP 中实现(array_search()使用自然排序,它对对象引用而不是它们的属性起作用) ,你必须像我一样自己实现它。

这种方法更有效(不再有深度) ,更重要的是通用性(假设您使用接口强制可比性) ,因为对象定义了它们的排序方式,所以您可以无限循环代码。好多了

<?php
$arr = array(0 => array("id"=>1,"name"=>"cat 1"),
1 => array("id"=>2,"name"=>"cat 2"),
2 => array("id"=>3,"name"=>"cat 1")
);
$arr = array_filter($arr, function($ar) {
return ($ar['name'] == 'cat 1');
//return ($ar['name'] == 'cat 1' AND $ar['id'] == '3');// you can add multiple conditions
});


echo "<pre>";
print_r($arr);


?>

档号: http://php.net/manual/en/function.array-filter.php

以下是解决方案:

<?php
$students['e1003']['birthplace'] = ("Mandaluyong <br>");
$students['ter1003']['birthplace'] = ("San Juan <br>");
$students['fgg1003']['birthplace'] = ("Quezon City <br>");
$students['bdf1003']['birthplace'] = ("Manila <br>");


$key = array_search('Delata Jona', array_column($students, 'name'));
echo $key;


?>
function findKey($tab, $key){
foreach($tab as $k => $value){
if($k==$key) return $value;
if(is_array($value)){
$find = findKey($value, $key);
if($find) return $find;
}
}
return null;
}

如果您想搜索键数组,这是很好的

function searchKeysInMultiDimensionalArray($array, $keys)
{
$results = array();


if (is_array($array)) {
$resultArray = array_intersect_key($array, array_flip($keys));
if (!empty($resultArray)) {
$results[] = $resultArray;
}


foreach ($array as $subarray) {
$results = array_merge($results, searchKeysInMultiDimensionalArray($subarray, $keys));
}
}


return $results;
}

键不会覆盖,因为每组键 = > 值将在结果数组中位于单独的数组中。
如果你不想要重复的钥匙,那么使用这一个

function searchKeysInMultiDimensionalArray($array, $keys)
{
$results = array();


if (is_array($array)) {
$resultArray = array_intersect_key($array, array_flip($keys));
if (!empty($resultArray)) {
foreach($resultArray as $key => $single) {


$results[$key] = $single;
}
}


foreach ($array as $subarray) {
$results = array_merge($results, searchKeysInMultiDimensionalArray($subarray, $keys));
}
}


return $results;
}

我认为最简单的方法是使用 php 数组函数,如果你知道你的关键。

function search_array ( $array, $key, $value )
{
return array_search($value,array_column($array,$key));
}

返回一个索引,你可以通过以下方式找到你想要的数据:

$arr = array(0 => array('id' => 1, 'name' => "cat 1"),
1 => array('id' => 2, 'name' => "cat 2"),
2 => array('id' => 3, 'name' => "cat 1")
);


echo json_encode($arr[search_array($arr,'name','cat 2')]);

这个输出将会:

{"id":2,"name":"cat 2"}

2个函数: array_search_key_value返回键的数组以到达一个具有多维数组中的值的键,array_extract_keys返回键数组所指向的多维数组中的值。

function array_search_key_value($array, $key, $value) {
if (!is_array($array)) {
return false;
}


return array_search_key_value_aux($array, $key, $value);
}


function array_search_key_value_aux($array, $key, $value, $path=null) {
if (array_key_exists($key, $array) && $array[$key] === $value) {
$path[]=$key;


return $path;
}


foreach ($array as $k => $v ) {
if (is_array($v)) {
$path[]=$k;


$p = array_search_key_value_aux($v, $key, $value, $path);


if ($p !== false) {
return $p;
}
}
}


return false;
}


function array_extract_keys($array, $key_list) {
$v = $array;


foreach ($key_list as $key) {
if (!is_array($v) || !array_key_exists($key, $v))
return false;


$v = &$v[$key];
}
       

return $v;
}

这里有一个统一的测试:

$test_array = array(
'a' => array(
'aa' => true,
'ab' => array(
'aaa' => array(
'one' => 1,
'two' => 2,
'three' => 3,
'four' => 4
),
'four' => 4,
'five' => 5,
),
'six' => 6,
),
'seven' => 7
);


$test_data = array(
array('one', 1),
array('two', 2),
array('three', 3),
array('four', 4),
array('five', 5),
array('six', 6),
array('seven', 7),
array('zero', 0),
array('one', 0),
);


foreach ($test_data as $d) {
$r = array_search_key_value($test_array, $d[0], $d[1]);


echo $d[0] . ' => ' . $d[1] . ' ? ', $r ? implode('/', $r) . ' => ' . array_extract_keys($test_array, $r) : 'null', PHP_EOL;
}