PHP多维数组搜索(按特定值查找键)


114

我有这个多维数组。我需要搜索它,仅返回与“ slug”的值匹配的键。我知道还有其他有关搜索多维数组的线程,但是我对这些情况的理解还不够。非常感谢您的帮助!

所以我需要一个像这样的函数:

myfunction($products,'breville-one-touch-tea-maker-BTM800XL');
// returns 1

这是数组:

$products = array (
1  => array(
        'name'          => 'The Breville One-Touch Tea Maker',
        'slug'          => 'breville-one-touch-tea-maker-BTM800XL',
        'shortname'     => 'The One-Touch Tea Maker',
        'listprice'     => '299.99',
        'price'         => '249.99',
        'rating'        => '9.5',
        'reviews'       => '81',
        'buyurl'        => 'http://www.amazon.com/The-Breville-One-Touch-Tea-Maker/dp/B003LNOPSG',
        'videoref1'     => 'xNb-FOTJY1c',
        'videoref2'     => 'WAyk-O2B6F8',
        'image'         => '812BpgHhjBML.jpg',
        'related1'      => '2',
        'related2'      => '3',
        'related3'      => '4',
        'bestbuy'       => '1',
        'quote'         => '',
        'quoteautor'    => 'K. Martino',
        ),

2  => array(
        'name'          => 'Breville Variable-Temperature Kettle BKE820XL',
        'slug'          => 'breville-variable-temperature-kettle-BKE820XL',
        'shortname'     => 'Variable Temperature Kettle',
        'listprice'     => '199.99',
        'price'         => '129.99',
        'rating'        => '9',
        'reviews'       => '78',
        'buyurl'        => 'http://www.amazon.com/Breville-BKE820XL-Variable-Temperature-1-8-Liter-Kettle/dp/B001DYERBK',
        'videoref1'     => 'oyZWBD83xeE',
        'image'         => '41y2B8jSKmwL.jpg',
        'related1'      => '3',
        'related2'      => '4',
        'related3'      => '5',
        'bestbuy'       => '1',
        'quote'         => '',
        'quoteautor'    => '',
        ),
);

Answers:


157

很简单:

function myfunction($products, $field, $value)
{
   foreach($products as $key => $product)
   {
      if ( $product[$field] === $value )
         return $key;
   }
   return false;
}

6
如果在条件语句中使用此函数,则将要对类型进行绝对检查,因为返回的键有时可能具有索引[0]。因此,如果进行条件检查,它应该看起来像这样: if (myfunction($array, 'field', 'value') !== FALSE )) // do something...
Andy Cook

159

另一个可能的解决方案基于该array_search()功能。您需要使用PHP 5.5.0或更高版本。

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

echo ("The key is: ".$key);
//This will output- The key is: 2

说明

该函数array_search()有两个参数。第一个是您要搜索的值。第二个是函数应该在哪里搜索。该函数array_column()获取key为的元素的值 'uid'

摘要

因此,您可以将其用作:

array_search('breville-one-touch-tea-maker-BTM800XL', array_column($products, 'slug'));

或者,如果您愿意:

// define function
function array_search_multidim($array, $column, $key){
    return (array_search($key, array_column($array, $column)));
}

// use it
array_search_multidim($products, 'slug', 'breville-one-touch-tea-maker-BTM800XL');

原始示例(由xfoxawy撰写)可以在DOCS上找到。
array_column() 页面


更新资料

由于Vael的评论,我很好奇,所以我做了一个简单的测试,以测量所用方法的性能array_search以及在接受的答案上提出的方法。

我创建了一个包含1000个数组的数组,其结构是这样的(所有数据都是随机的):

[
      {
            "_id": "57fe684fb22a07039b3f196c",
            "index": 0,
            "guid": "98dd3515-3f1e-4b89-8bb9-103b0d67e613",
            "isActive": true,
            "balance": "$2,372.04",
            "picture": "http://placehold.it/32x32",
            "age": 21,
            "eyeColor": "blue",
            "name": "Green",
            "company": "MIXERS"
      },...
]

我运行搜索测试100次,为name字段搜索了不同的值,然后计算了以毫秒为单位的平均时间。在这里您可以看到一个示例。

结果是,针对此答案提出的方法大约需要2E-7才能找到值,而可接受的答案方法大约需要8E-7。

就像我之前说过的,对于使用具有此大小的数组的应用程序,这两种情况都可以接受。如果大小增长很多,比如说1M个元素,那么这个小差异也会增加。

更新二

我在此方法的基础上添加了一个测试,array_walk_recursive其中提到了一些答案。得到的结果是正确的。而且,如果我们专注于性能,它会比测试中的其他性能差一些。在测试中,您可以看到它比基于array_search。同样,对于大多数应用程序而言,这并不是非常相关的差异。

更新三

感谢@mickmackusa发现此方法的一些限制:

  • 此方法将在关联键上失败。
  • 此方法仅适用于索引子数组(从0开始并具有连续升序的键)。

有谁知道它的表现?看来最终会更慢,仍然需要5.5。我无法使用5.4进行测试。
Vael Victus '16

对于任何不了解的人:在php 7中,for循环更快。在该示例中,当我将其更改为5.6时,array_search的速度略快。
Vael Victus '16

聪明!我在做类似的事情,使用array_combine()和array_column()来制作另一个数组,用已知的密钥从中获取我的数据,但这更加优雅。
大卫

4
array_search()与with一起使用array_column()不适用于OP的示例数组,因为子数组键始于1。此方法还将在关联键上失败。此方法仅适用于索引子数组(从0键开始并具有连续升序键)。这样做的原因是因为array_column()它将在其返回的数组中生成新的索引。
mickmackusa

完全正确@mickmackusa,我已经将您的知识添加到了答案中。感谢您的帮助
伊万·罗德里格斯·托雷斯

14

此类方法可以通过多种条件在数组中搜索:

class Stdlib_Array
{
    public static function multiSearch(array $array, array $pairs)
    {
        $found = array();
        foreach ($array as $aKey => $aVal) {
            $coincidences = 0;
            foreach ($pairs as $pKey => $pVal) {
                if (array_key_exists($pKey, $aVal) && $aVal[$pKey] == $pVal) {
                    $coincidences++;
                }
            }
            if ($coincidences == count($pairs)) {
                $found[$aKey] = $aVal;
            }
        }

        return $found;
    }    
}

// Example:

$data = array(
    array('foo' => 'test4', 'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test1', 'bar' => 'baz3'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz4'),
    array('foo' => 'test4', 'bar' => 'baz1'),
    array('foo' => 'test',  'bar' => 'baz1'),
    array('foo' => 'test3', 'bar' => 'baz2'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test',  'bar' => 'baz'),
    array('foo' => 'test4', 'bar' => 'baz1')
);

$result = Stdlib_Array::multiSearch($data, array('foo' => 'test4', 'bar' => 'baz1'));

var_dump($result);

将产生:

array(2) {
  [5]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
  [10]=>
  array(2) {
    ["foo"]=>
    string(5) "test4"
    ["bar"]=>
    string(4) "baz1"
  }
}

嗨宿命论者stackoverflow.com/questions/40860030/...。已重新回答这些问题,您能否请您澄清该问题
KARTHI SRV

4

使用此功能:

function searchThroughArray($search,array $lists){
        try{
            foreach ($lists as $key => $value) {
                if(is_array($value)){
                    array_walk_recursive($value, function($v, $k) use($search ,$key,$value,&$val){
                        if(strpos($v, $search) !== false )  $val[$key]=$value;
                    });
            }else{
                    if(strpos($value, $search) !== false )  $val[$key]=$value;
                }

            }
            return $val;

        }catch (Exception $e) {
            return false;
        }
    }

和通话功能。

print_r(searchThroughArray('breville-one-touch-tea-maker-BTM800XL',$products));

好答案。您可以检查我的回答你的建议的性能
伊万·罗德里格斯·托雷斯

仅代码的答案在StackOverflow上的价值很小。请更新您的帖子以解释您的叶节点子字符串搜索功能的工作方式。此方法不是专门为OP要求而设计的,因此弄清差异非常重要。演示链接将大大提高读者的理解力。始终发布答案,以教育OP和更多的SO读者。
mickmackusa

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

仅代码的答案在StackOverflow上的价值很小。请更新您的帖子,以解释递归方法的工作原理,适当的情况以及不必要的递归开销。始终发布答案,以教育OP和更多的SO读者。
mickmackusa

1

对于下一个来访者:使用递归数组遍历;它访问多维数组中的每个“叶子”。这里是启发:

function getMDArrayValueByKey($a, $k) {
    $r = [];
    array_walk_recursive ($a, 
                          function ($item, $key) use ($k, &$r) {if ($key == $k) $r[] = $item;}
                          );
    return $r;
}

没问题!只是为了节省您的时间,如果您尝试使用josef答案,该函数将返回一个包含一个元素的数组。关键是想要的答案:)
伊万·罗德里格斯·托雷斯

@伊万·约瑟夫(Ivan josef)的答案与此截然不同。你自己测试过了吗?我一直在关注这个答案,但我认为它无法正常工作,因为array_walk_recursive无法看到一个级别。对于每个第一级密钥,josef都在调用strpos或检查所有叶节点。看到不同?
mickmackusa

当然,@ mickmackusa但是,汉斯给出了一些启发,答案并不是从字面上给出解决方案。正如约瑟夫(Josef)所做的那样,它需要更多的阐述。但是,您的意思是,该答案不能完全解决问题。
伊万·罗德里格斯·托雷斯

1

我想在下面说,$products一开始在问题中给出的实际数组在哪里。

print_r(
  array_search("breville-variable-temperature-kettle-BKE820XL", 
  array_map(function($product){return $product["slug"];},$products))
);

0

试试这个

function recursive_array_search($needle,$haystack) {
        foreach($haystack as $key=>$value) {
            $current_key=$key;
            if($needle==$value['uid'] OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
                return $current_key;
            }
        }
        return false;
    }

仅代码的答案在StackOverflow上的价值很小。请更新您的帖子,以解释递归方法的工作原理,适当的情况以及不必要的递归开销。始终发布答案,以教育OP和更多的SO读者。附言:我想大多数PHP开发人员会更喜欢&&||,而不是ANDOR你的条件。没有理由宣布current_key。比较$needle应该严格。
mickmackusa
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.