简体   繁体   English

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

[英]How to search by key=>value in a multidimensional array in PHP

Is there any fast way to get all subarrays where a key value pair was found in a multidimensional array?有没有什么快速的方法来获取在多维数组中找到键值对的所有子数组? I can't say how deep the array will be.我不能说阵列有多深。

Simple example array:简单示例数组:

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

When I search for key=name and value="cat 1" the function should return:当我搜索 key=name 和 value="cat 1" 时,该函数应返回:

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

I guess the function has to be recursive to get down to the deepest level.我猜这个函数必须是递归的才能达到最深层次。

Code:代码:

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

Output:输出:

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

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

)

If efficiency is important you could write it so all the recursive calls store their results in the same temporary $results array rather than merging arrays together, like so:如果效率很重要,您可以编写它,以便所有递归调用将其结果存储在同一个临时$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);
    }
}

The key there is that search_r takes its fourth parameter by reference rather than by value;关键是search_r通过引用而不是通过值来获取它的第四个参数; the ampersand & is crucial. &符号&是至关重要的。

FYI: If you have an older version of PHP then you have to specify the pass-by-reference part in the call to search_r rather than in its declaration.仅供参考:如果您使用的是旧版本的 PHP,那么您必须在对search_r调用中而不是在其声明中指定传递引用部分。 That is, the last line becomes search_r($subarray, $key, $value, &$results) .也就是说,最后一行变成search_r($subarray, $key, $value, &$results)

How about the SPL version instead? SPL版本怎么样? It'll save you some typing:它将为您节省一些输入:

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

What's great is that basically the same code will iterate through a directory for you, by using a RecursiveDirectoryIterator instead of a RecursiveArrayIterator.很棒的是,基本上相同的代码将通过使用 RecursiveDirectoryIterator 而不是 RecursiveArrayIterator 为您遍历一个目录。 SPL is the roxor. SPL 是 roxor。

The only bummer about SPL is that it's badly documented on the web.关于 SPL 的唯一遗憾是它在网络上的记录很糟糕。 But several PHP books go into some useful detail, particularly Pro PHP;但是有几本 PHP 书籍介绍了一些有用的细节,尤其是 Pro PHP; and you can probably google for more info, too.你也可以谷歌搜索更多信息。

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

?>

Ref: http://php.net/manual/en/function.array-filter.php参考: http : //php.net/manual/en/function.array-filter.php

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

对快速版本的小幅改进。

Came back to post this update for anyone needing an optimisation tip on these answers, particulary John Kugelman's great answer up above.回来为任何需要有关这些答案的优化提示的人发布此更新,尤其是上面约翰·库格曼 (John Kugelman) 的精彩回答。

His posted function work fine but I had to optimize this scenario for handling a 12 000 row resultset.他发布的函数工作正常,但我必须优化此场景以处理 12 000 行结果集。 The function was taking an eternal 8 secs to go through all records, waaaaaay too long.该函数需要一个永恒的 8 秒来遍历所有记录,太长了。

I simply needed the function to STOP searching and return when match was found.我只需要在找到匹配项时停止搜索并返回的功能。 Ie, if searching for a customer_id, we know we only have one in the resultset and once we find the customer_id in the multidimensional array, we want to return.即,如果搜索 customer_id,我们知道结果集中只有一个,一旦我们在多维数组中找到 customer_id,我们就想返回。

Here is the speed-optimised ( and much simplified ) version of this function, for anyone in need.这是此功能的速度优化(和大大简化)版本,适用于任何需要的人。 Unlike other version, it can only handle only one depth of array, does not recurse and does away with merging multiple results.与其他版本不同的是,它只能处理一个深度的数组,不会递归,并且不需要合并多个结果。

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

This brought down the the task to match the 12 000 records to a 1.5 secs.这降低了将 12 000 条记录匹配到 1.5 秒的任务。 Still very costly but much more reasonable.仍然非常昂贵,但更合理。

Be careful of linear search algorithms (the above are linear) in multiple dimensional arrays as they have compounded complexity as its depth increases the number of iterations required to traverse the entire array.小心多维数组中的线性搜索算法(以上是线性的),因为它们的复杂性增加了,因为其深度增加了遍历整个数组所需的迭代次数。 Eg:例如:

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

would take at the most 200 iterations to find what you are looking for (if the needle were at [100][1]), with a suitable algorithm.使用合适的算法最多需要 200 次迭代才能找到您要查找的内容(如果指针位于 [100][1])。

Linear algorithms in this case perform at O(n) (order total number of elements in entire array), this is poor, a million entries (eg a 1000x100x10 array) would take on average 500,000 iterations to find the needle.在这种情况下,线性算法以 O(n) 执行(排序整个数组中元素的总数),这很糟糕,一百万个条目(例如 1000x100x10 数组)平均需要 500,000 次迭代才能找到针。 Also what would happen if you decided to change the structure of your multidimensional array?如果您决定更改多维数组的结构,会发生什么? And PHP would kick out a recursive algorithm if your depth was more than 100. Computer science can do better:如果深度超过 100,PHP 会踢出递归算法。计算机科学可以做得更好:

Where possible, always use objects instead of multiple dimensional arrays:在可能的情况下,始终使用对象而不是多维数组:

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

and apply a custom comparator interface and function to sort and find them:并应用自定义比较器接口和函数来排序和查找它们:

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

You can use uasort() to utilize a custom comparator, if you're feeling adventurous you should implement your own collections for your objects that can sort and manage them (I always extend ArrayObject to include a search function at the very least).您可以使用uasort()来利用自定义比较器,如果您喜欢冒险,您应该为可以排序和管理它们的对象实现自己的集合(我总是扩展 ArrayObject 以至少包含搜索功能)。

$arrayObj->uasort("myComp");

Once they are sorted (uasort is O(n log n), which is as good as it gets over arbitrary data), binary search can do the operation in O(log n) time, ie a million entries only takes ~20 iterations to search.一旦它们被排序(uasort 是 O(n log n),这与它获取任意数据一样好),二分搜索可以在 O(log n) 时间内完成操作,即一百万个条目只需要约 20 次迭代搜索。 As far as I am aware custom comparator binary search is not implemented in PHP ( array_search() uses natural ordering which works on object references not their properties), you would have to implement this your self like I do.据我所知,自定义比较器二进制搜索未在 PHP 中实现( array_search()使用自然排序,它适用于对象引用而不是它们的属性),您必须像我一样自己实现它。

This approach is more efficient (there is no longer a depth) and more importantly universal (assuming you enforce comparability using interfaces) since objects define how they are sorted, so you can recycle the code infinitely.这种方法更有效(不再有深度),更重要的是通用(假设您使用接口强制执行可比性),因为对象定义了它们的排序方式,因此您可以无限地回收代码。 Much better =)好多了=)

Here is solution:这是解决方案:

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

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

http://snipplr.com/view/51108/nested-array-search-by-value-or-key/ 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;
} 

I needed something similar, but to search for multidimensional array by value... I took John example and wrote我需要类似的东西,但是要按值搜索多维数组...我以约翰为例并写道

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

I hope it helps somebody :)我希望它可以帮助某人:)

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

This is a revised function from the one that John K. posted... I need to grab only the specific key in the array and nothing above it.这是 John 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'));

I think the easiest way is using php array functions if you know your key.如果您知道您的密钥,我认为最简单的方法是使用 php 数组函数。

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

this return an index that you could find your desired data by this like below:这将返回一个索引,您可以通过如下方式找到所需的数据:

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

this output will:此输出将:

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

And another version that returns the key value from the array element in which the value is found (no recursion, optimized for speed):另一个版本从找到该值的数组元素返回键值(无递归,针对速度进行了优化):

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

Thanks to all who posted here.感谢所有在这里发帖的人。

If you want to search for array of keys this is good如果您想搜索键数组,这很好

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

Keys will not overwrite because each set of key => values will be in separate array in resulting array.键不会覆盖,因为每组键 => 值将在结果数组中的单独数组中。
If you don't want duplicate keys then use this one如果您不想要重复的键,请使用此键

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

2 functions: array_search_key_value which returns the array of keys to reach a key with a value in a multidimensional array, array_extract_keys which returns the value in a multidimensional array pointed to by an array of keys. 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;
}

Here is a unitary test:这是一个单一的测试:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM